1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/*
25 * Xbios SDL video driver
26 *
27 * Patrice Mandin
28 */
29
30#include <sys/stat.h>
31#include <unistd.h>
32
33/* Mint includes */
34#include <mint/cookie.h>
35#include <mint/osbind.h>
36#include <mint/falcon.h>
37
38#include "SDL_video.h"
39#include "SDL_mouse.h"
40#include "../SDL_sysvideo.h"
41#include "../SDL_pixels_c.h"
42#include "../../events/SDL_events_c.h"
43
44#include "../ataricommon/SDL_ataric2p_s.h"
45#include "../ataricommon/SDL_atarievents_c.h"
46#include "../ataricommon/SDL_atarimxalloc_c.h"
47#include "../ataricommon/SDL_atarigl_c.h"
48#include "SDL_xbios.h"
49#include "SDL_xbios_blowup.h"
50#include "SDL_xbios_centscreen.h"
51#include "SDL_xbios_sb3.h"
52#include "SDL_xbios_tveille.h"
53#include "SDL_xbios_milan.h"
54
55#define XBIOS_VID_DRIVER_NAME "xbios"
56
57#ifndef C_fVDI
58#define C_fVDI 0x66564449L
59#endif
60
61/* Debug print info */
62#if 0
63#define DEBUG_PRINT(what) \
64	{ \
65		printf what; \
66	}
67#define DEBUG_VIDEO_XBIOS 1
68#else
69#define DEBUG_PRINT(what)
70#undef DEBUG_VIDEO_XBIOS
71#endif
72
73/* Initialization/Query functions */
74static int XBIOS_VideoInit(_THIS, SDL_PixelFormat *vformat);
75static SDL_Rect **XBIOS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
76static SDL_Surface *XBIOS_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
77static int XBIOS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
78static void XBIOS_VideoQuit(_THIS);
79
80/* Hardware surface functions */
81static int XBIOS_AllocHWSurface(_THIS, SDL_Surface *surface);
82static int XBIOS_LockHWSurface(_THIS, SDL_Surface *surface);
83static int XBIOS_FlipHWSurface(_THIS, SDL_Surface *surface);
84static void XBIOS_UnlockHWSurface(_THIS, SDL_Surface *surface);
85static void XBIOS_FreeHWSurface(_THIS, SDL_Surface *surface);
86static void XBIOS_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
87
88#if SDL_VIDEO_OPENGL
89/* OpenGL functions */
90static void XBIOS_GL_SwapBuffers(_THIS);
91#endif
92
93/* To setup palette */
94
95static unsigned short	TT_palette[256];
96static unsigned long	F30_palette[256];
97
98/* Default list of video modes */
99
100static const xbiosmode_t stmodes[1]={
101	{ST_LOW>>8,320,200,4, XBIOSMODE_C2P}
102};
103
104static const xbiosmode_t ttmodes[2]={
105	{TT_LOW,320,480,8, XBIOSMODE_C2P},
106	{TT_LOW,320,240,8, XBIOSMODE_C2P|XBIOSMODE_DOUBLELINE}
107};
108
109static const xbiosmode_t falconrgbmodes[16]={
110	{BPS16|COL80|OVERSCAN|VERTFLAG,768,480,16,0},
111	{BPS16|COL80|OVERSCAN,768,240,16,0},
112	{BPS16|COL80|VERTFLAG,640,400,16,0},
113	{BPS16|COL80,640,200,16,0},
114	{BPS16|OVERSCAN|VERTFLAG,384,480,16,0},
115	{BPS16|OVERSCAN,384,240,16,0},
116	{BPS16|VERTFLAG,320,400,16,0},
117	{BPS16,320,200,16,0},
118	{BPS8|COL80|OVERSCAN|VERTFLAG,768,480,8,XBIOSMODE_C2P},
119	{BPS8|COL80|OVERSCAN,768,240,8,XBIOSMODE_C2P},
120	{BPS8|COL80|VERTFLAG,640,400,8,XBIOSMODE_C2P},
121	{BPS8|COL80,640,200,8,XBIOSMODE_C2P},
122	{BPS8|OVERSCAN|VERTFLAG,384,480,8,XBIOSMODE_C2P},
123	{BPS8|OVERSCAN,384,240,8,XBIOSMODE_C2P},
124	{BPS8|VERTFLAG,320,400,8,XBIOSMODE_C2P},
125	{BPS8,320,200,8,XBIOSMODE_C2P}
126};
127
128static const xbiosmode_t falconvgamodes[6]={
129	{BPS16,320,480,16,0},
130	{BPS16|VERTFLAG,320,240,16,0},
131	{BPS8|COL80,640,480,8,XBIOSMODE_C2P},
132	{BPS8|COL80|VERTFLAG,640,240,8,XBIOSMODE_C2P},
133	{BPS8,320,480,8,XBIOSMODE_C2P},
134	{BPS8|VERTFLAG,320,240,8,XBIOSMODE_C2P}
135};
136
137/* Xbios driver bootstrap functions */
138
139static int XBIOS_Available(void)
140{
141	long cookie_vdo, /*cookie_mil,*/ cookie_hade, cookie_scpn;
142	long cookie_fvdi;
143	const char *envr = SDL_getenv("SDL_VIDEODRIVER");
144
145	/* Milan/Hades Atari clones do not have an Atari video chip */
146	if ( /*(Getcookie(C__MIL, &cookie_mil) == C_FOUND) ||*/
147		(Getcookie(C_hade, &cookie_hade) == C_FOUND) ) {
148		return 0;
149	}
150
151	/* fVDI means graphic card, so no Xbios with it */
152	if (Getcookie(C_fVDI, &cookie_fvdi) == C_FOUND) {
153		if (!envr) {
154			return 0;
155		}
156		if (SDL_strcmp(envr, XBIOS_VID_DRIVER_NAME)!=0) {
157			return 0;
158		}
159		/* Except if we force Xbios usage, through env var */
160	}
161
162	/* Cookie _VDO present ? if not, assume ST machine */
163	if (Getcookie(C__VDO, &cookie_vdo) != C_FOUND) {
164		cookie_vdo = VDO_ST << 16;
165	}
166
167	/* Test if we have a monochrome monitor plugged in */
168	switch( cookie_vdo >>16) {
169		case VDO_ST:
170		case VDO_STE:
171			if ( Getrez() == (ST_HIGH>>8) )
172				return 0;
173			break;
174		case VDO_TT:
175			if ( (EgetShift() & ES_MODE) == TT_HIGH)
176				return 0;
177			break;
178		case VDO_F30:
179			if ( VgetMonitor() == MONITOR_MONO)
180				return 0;
181			if (Getcookie(C_SCPN, &cookie_scpn) == C_FOUND) {
182				if (!SDL_XBIOS_SB3Usable((scpn_cookie_t *)cookie_scpn)) {
183					return 0;
184				}
185			}
186			break;
187		case VDO_MILAN:
188			break;
189		default:
190			return 0;
191	}
192
193	return 1;
194}
195
196static void XBIOS_DeleteDevice(SDL_VideoDevice *device)
197{
198	SDL_free(device->hidden);
199	SDL_free(device);
200}
201
202static SDL_VideoDevice *XBIOS_CreateDevice(int devindex)
203{
204	SDL_VideoDevice *device;
205
206	/* Initialize all variables that we clean on shutdown */
207	device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
208	if ( device ) {
209		SDL_memset(device, 0, (sizeof *device));
210		device->hidden = (struct SDL_PrivateVideoData *)
211				SDL_malloc((sizeof *device->hidden));
212		device->gl_data = (struct SDL_PrivateGLData *)
213				SDL_malloc((sizeof *device->gl_data));
214	}
215	if ( (device == NULL) || (device->hidden == NULL) ) {
216		SDL_OutOfMemory();
217		if ( device ) {
218			SDL_free(device);
219		}
220		return(0);
221	}
222	SDL_memset(device->hidden, 0, (sizeof *device->hidden));
223	SDL_memset(device->gl_data, 0, sizeof(*device->gl_data));
224
225	/* Video functions */
226	device->VideoInit = XBIOS_VideoInit;
227	device->ListModes = XBIOS_ListModes;
228	device->SetVideoMode = XBIOS_SetVideoMode;
229	device->SetColors = XBIOS_SetColors;
230	device->UpdateRects = NULL;
231	device->VideoQuit = XBIOS_VideoQuit;
232	device->AllocHWSurface = XBIOS_AllocHWSurface;
233	device->LockHWSurface = XBIOS_LockHWSurface;
234	device->UnlockHWSurface = XBIOS_UnlockHWSurface;
235	device->FlipHWSurface = XBIOS_FlipHWSurface;
236	device->FreeHWSurface = XBIOS_FreeHWSurface;
237
238#if SDL_VIDEO_OPENGL
239	/* OpenGL functions */
240	device->GL_LoadLibrary = SDL_AtariGL_LoadLibrary;
241	device->GL_GetProcAddress = SDL_AtariGL_GetProcAddress;
242	device->GL_GetAttribute = SDL_AtariGL_GetAttribute;
243	device->GL_MakeCurrent = SDL_AtariGL_MakeCurrent;
244	device->GL_SwapBuffers = XBIOS_GL_SwapBuffers;
245#endif
246
247	/* Events */
248	device->InitOSKeymap = Atari_InitOSKeymap;
249	device->PumpEvents = Atari_PumpEvents;
250
251	device->free = XBIOS_DeleteDevice;
252
253	return device;
254}
255
256VideoBootStrap XBIOS_bootstrap = {
257	XBIOS_VID_DRIVER_NAME, "Atari Xbios driver",
258	XBIOS_Available, XBIOS_CreateDevice
259};
260
261void SDL_XBIOS_AddMode(_THIS, int actually_add, const xbiosmode_t *modeinfo)
262{
263	int i = 0;
264
265	switch(modeinfo->depth) {
266		case 15:
267		case 16:
268			i = 1;
269			break;
270		case 24:
271			i = 2;
272			break;
273		case 32:
274			i = 3;
275			break;
276	}
277
278	if ( actually_add ) {
279		SDL_Rect saved_rect[2];
280		xbiosmode_t saved_mode[2];
281		int b, j;
282
283		/* Add the mode, sorted largest to smallest */
284		b = 0;
285		j = 0;
286		while ( (SDL_modelist[i][j]->w > modeinfo->width) ||
287			(SDL_modelist[i][j]->h > modeinfo->height) ) {
288			++j;
289		}
290		/* Skip modes that are already in our list */
291		if ( (SDL_modelist[i][j]->w == modeinfo->width) &&
292		     (SDL_modelist[i][j]->h == modeinfo->height) ) {
293			return;
294		}
295		/* Insert the new mode */
296		saved_rect[b] = *SDL_modelist[i][j];
297		SDL_memcpy(&saved_mode[b], SDL_xbiosmode[i][j], sizeof(xbiosmode_t));
298		SDL_modelist[i][j]->w = modeinfo->width;
299		SDL_modelist[i][j]->h = modeinfo->height;
300		SDL_memcpy(SDL_xbiosmode[i][j], modeinfo, sizeof(xbiosmode_t));
301		/* Everybody scoot down! */
302		if ( saved_rect[b].w && saved_rect[b].h ) {
303		    for ( ++j; SDL_modelist[i][j]->w; ++j ) {
304			saved_rect[!b] = *SDL_modelist[i][j];
305			memcpy(&saved_mode[!b], SDL_xbiosmode[i][j], sizeof(xbiosmode_t));
306			*SDL_modelist[i][j] = saved_rect[b];
307			SDL_memcpy(SDL_xbiosmode[i][j], &saved_mode[b], sizeof(xbiosmode_t));
308			b = !b;
309		    }
310		    *SDL_modelist[i][j] = saved_rect[b];
311		    SDL_memcpy(SDL_xbiosmode[i][j], &saved_mode[b], sizeof(xbiosmode_t));
312		}
313	} else {
314		++SDL_nummodes[i];
315	}
316}
317
318static void XBIOS_ListSTModes(_THIS, int actually_add)
319{
320	SDL_XBIOS_AddMode(this, actually_add, &stmodes[0]);
321}
322
323static void XBIOS_ListTTModes(_THIS, int actually_add)
324{
325	int i;
326
327	for (i=0; i<2; i++) {
328		SDL_XBIOS_AddMode(this, actually_add, &ttmodes[i]);
329	}
330}
331
332static void XBIOS_ListFalconRgbModes(_THIS, int actually_add)
333{
334	int i;
335
336	for (i=0; i<16; i++) {
337		xbiosmode_t modeinfo;
338
339		SDL_memcpy(&modeinfo, &falconrgbmodes[i], sizeof(xbiosmode_t));
340		modeinfo.number &= ~(VGA|PAL);
341		modeinfo.number |= XBIOS_oldvmode & (VGA|PAL);
342
343		SDL_XBIOS_AddMode(this, actually_add, &modeinfo);
344	}
345}
346
347static void XBIOS_ListFalconVgaModes(_THIS, int actually_add)
348{
349	int i;
350
351	for (i=0; i<6; i++) {
352		xbiosmode_t modeinfo;
353
354		SDL_memcpy(&modeinfo, &falconvgamodes[i], sizeof(xbiosmode_t));
355		modeinfo.number &= ~(VGA|PAL);
356		modeinfo.number |= XBIOS_oldvmode & (VGA|PAL);
357
358		SDL_XBIOS_AddMode(this, actually_add, &modeinfo);
359	}
360}
361
362static int XBIOS_VideoInit(_THIS, SDL_PixelFormat *vformat)
363{
364	int i;
365	long cookie_blow, cookie_scpn, cookie_cnts;
366
367	/* Initialize all variables that we clean on shutdown */
368	for ( i=0; i<NUM_MODELISTS; ++i ) {
369		SDL_nummodes[i] = 0;
370		SDL_modelist[i] = NULL;
371		SDL_xbiosmode[i] = NULL;
372	}
373
374	/* Cookie _VDO present ? if not, assume ST machine */
375	if (Getcookie(C__VDO, &XBIOS_cvdo) != C_FOUND) {
376		XBIOS_cvdo = VDO_ST << 16;
377	}
378
379	/* Allocate memory for old palette */
380	XBIOS_oldpalette = (void *)SDL_malloc(256*sizeof(long));
381	if ( !XBIOS_oldpalette ) {
382		SDL_SetError("Unable to allocate memory for old palette\n");
383		return(-1);
384	}
385
386	/* Initialize video mode list */
387	/* and save current screen status (palette, screen address, video mode) */
388	XBIOS_centscreen = SDL_FALSE;
389	XBIOS_oldvbase = Physbase();
390
391	/* Determine the current screen size */
392	this->info.current_w = 0;
393	this->info.current_h = 0;
394
395	/* Determine the screen depth (use default 8-bit depth) */
396	vformat->BitsPerPixel = 8;
397
398	/* First allocate room for needed video modes */
399	switch (XBIOS_cvdo >>16) {
400		case VDO_ST:
401		case VDO_STE:
402			{
403				short *oldpalette;
404
405				XBIOS_oldvmode=Getrez();
406				switch(XBIOS_oldvmode << 8) {
407					case ST_LOW:
408						XBIOS_oldnumcol=16;
409						break;
410					case ST_MED:
411						XBIOS_oldnumcol=4;
412						break;
413					case ST_HIGH:
414						XBIOS_oldnumcol=2;
415						break;
416				}
417
418				oldpalette= (short *) XBIOS_oldpalette;
419				for (i=0;i<XBIOS_oldnumcol;i++) {
420					*oldpalette++=Setcolor(i,-1);
421				}
422
423				XBIOS_ListSTModes(this, 0);
424			}
425			break;
426		case VDO_TT:
427			XBIOS_oldvmode=EgetShift();
428
429			switch(XBIOS_oldvmode & ES_MODE) {
430				case TT_LOW:
431					XBIOS_oldnumcol=256;
432					break;
433				case ST_LOW:
434				case TT_MED:
435					XBIOS_oldnumcol=16;
436					break;
437				case ST_MED:
438					XBIOS_oldnumcol=4;
439					break;
440				case ST_HIGH:
441				case TT_HIGH:
442					XBIOS_oldnumcol=2;
443					break;
444			}
445			if (XBIOS_oldnumcol) {
446				EgetPalette(0, XBIOS_oldnumcol, XBIOS_oldpalette);
447			}
448
449			XBIOS_ListTTModes(this, 0);
450			break;
451		case VDO_F30:
452			XBIOS_oldvmode=VsetMode(-1);
453
454			XBIOS_oldnumcol= 1<< (1 << (XBIOS_oldvmode & NUMCOLS));
455			if (XBIOS_oldnumcol > 256) {
456				XBIOS_oldnumcol = 0;
457			}
458			if (XBIOS_oldnumcol) {
459				VgetRGB(0, XBIOS_oldnumcol, XBIOS_oldpalette);
460			}
461
462			vformat->BitsPerPixel = 16;
463
464			/* ScreenBlaster 3 ? */
465			if (Getcookie(C_SCPN, &cookie_scpn) == C_FOUND) {
466				SDL_XBIOS_ListSB3Modes(this, 0, (scpn_cookie_t *)cookie_scpn);
467			} else
468			/* Centscreen ? */
469			if (Getcookie(C_CNTS, &cookie_cnts) == C_FOUND) {
470				XBIOS_oldvmode = SDL_XBIOS_ListCentscreenModes(this, 0);
471				XBIOS_centscreen = SDL_TRUE;
472			} else
473			/* Standard, with or without Blowup */
474			{
475				switch (VgetMonitor())
476				{
477					case MONITOR_RGB:
478					case MONITOR_TV:
479						XBIOS_ListFalconRgbModes(this, 0);
480						break;
481					case MONITOR_VGA:
482						XBIOS_ListFalconVgaModes(this, 0);
483						break;
484				}
485
486				if (Getcookie(C_BLOW, &cookie_blow) == C_FOUND) {
487					SDL_XBIOS_ListBlowupModes(this, 0, (blow_cookie_t *)cookie_blow);
488				}
489			}
490			break;
491		case VDO_MILAN:
492			{
493				SCREENINFO si;
494
495				/* Read infos about current mode */
496				VsetScreen(-1, &XBIOS_oldvmode, MI_MAGIC, CMD_GETMODE);
497
498				si.size = sizeof(SCREENINFO);
499				si.devID = XBIOS_oldvmode;
500				si.scrFlags = 0;
501				VsetScreen(-1, &si, MI_MAGIC, CMD_GETINFO);
502
503				this->info.current_w = si.scrWidth;
504				this->info.current_h = si.scrHeight;
505
506				XBIOS_oldnumcol = 0;
507				if (si.scrFlags & SCRINFO_OK) {
508					if (si.scrPlanes <= 8) {
509						XBIOS_oldnumcol = 1<<si.scrPlanes;
510					}
511				}
512				if (XBIOS_oldnumcol) {
513					VgetRGB(0, XBIOS_oldnumcol, XBIOS_oldpalette);
514				}
515
516				SDL_XBIOS_ListMilanModes(this, 0);
517			}
518			break;
519	}
520
521	for ( i=0; i<NUM_MODELISTS; ++i ) {
522		int j;
523
524		SDL_xbiosmode[i] = (xbiosmode_t **)
525			SDL_malloc((SDL_nummodes[i]+1)*sizeof(xbiosmode_t *));
526		if ( SDL_xbiosmode[i] == NULL ) {
527			SDL_OutOfMemory();
528			return(-1);
529		}
530		for ( j=0; j<SDL_nummodes[i]; ++j ) {
531			SDL_xbiosmode[i][j]=(xbiosmode_t *)SDL_malloc(sizeof(xbiosmode_t));
532			if ( SDL_xbiosmode[i][j] == NULL ) {
533				SDL_OutOfMemory();
534				return(-1);
535			}
536			SDL_memset(SDL_xbiosmode[i][j], 0, sizeof(xbiosmode_t));
537		}
538		SDL_xbiosmode[i][j] = NULL;
539
540		SDL_modelist[i] = (SDL_Rect **)
541				SDL_malloc((SDL_nummodes[i]+1)*sizeof(SDL_Rect *));
542		if ( SDL_modelist[i] == NULL ) {
543			SDL_OutOfMemory();
544			return(-1);
545		}
546		for ( j=0; j<SDL_nummodes[i]; ++j ) {
547			SDL_modelist[i][j]=(SDL_Rect *)SDL_malloc(sizeof(SDL_Rect));
548			if ( SDL_modelist[i][j] == NULL ) {
549				SDL_OutOfMemory();
550				return(-1);
551			}
552			SDL_memset(SDL_modelist[i][j], 0, sizeof(SDL_Rect));
553		}
554		SDL_modelist[i][j] = NULL;
555	}
556
557	/* Now fill the mode list */
558	switch (XBIOS_cvdo >>16) {
559		case VDO_ST:
560		case VDO_STE:
561			XBIOS_ListSTModes(this, 1);
562			break;
563		case VDO_TT:
564			XBIOS_ListTTModes(this, 1);
565			break;
566		case VDO_F30:
567			/* ScreenBlaster 3 ? */
568			if (Getcookie(C_SCPN, &cookie_scpn) == C_FOUND) {
569				SDL_XBIOS_ListSB3Modes(this, 1, (scpn_cookie_t *)cookie_scpn);
570			} else
571			/* Centscreen ? */
572			if (Getcookie(C_CNTS, &cookie_cnts) == C_FOUND) {
573				XBIOS_oldvmode = SDL_XBIOS_ListCentscreenModes(this, 1);
574				XBIOS_centscreen = SDL_TRUE;
575			} else
576			/* Standard, with or without Blowup */
577			{
578				switch (VgetMonitor())
579				{
580					case MONITOR_RGB:
581					case MONITOR_TV:
582						XBIOS_ListFalconRgbModes(this, 1);
583						break;
584					case MONITOR_VGA:
585						XBIOS_ListFalconVgaModes(this, 1);
586						break;
587				}
588
589				if (Getcookie(C_BLOW, &cookie_blow) == C_FOUND) {
590					SDL_XBIOS_ListBlowupModes(this, 1, (blow_cookie_t *)cookie_blow);
591				}
592			}
593			break;
594		case VDO_MILAN:
595			SDL_XBIOS_ListMilanModes(this, 1);
596			break;
597	}
598
599	XBIOS_screens[0]=NULL;
600	XBIOS_screens[1]=NULL;
601	XBIOS_shadowscreen=NULL;
602
603	/* Update hardware info */
604	this->info.hw_available = 1;
605	this->info.video_mem = (Uint32) Atari_SysMalloc(-1L, MX_STRAM);
606
607	/* Init chunky to planar routine */
608	SDL_Atari_C2pConvert = SDL_Atari_C2pConvert8;
609
610#if SDL_VIDEO_OPENGL
611	SDL_AtariGL_InitPointers(this);
612#endif
613
614	/* Disable screensavers */
615	if (SDL_XBIOS_TveillePresent(this)) {
616		SDL_XBIOS_TveilleDisable(this);
617	}
618
619	/* We're done! */
620	return(0);
621}
622
623static SDL_Rect **XBIOS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
624{
625	return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
626}
627
628static void XBIOS_FreeBuffers(_THIS)
629{
630	int i;
631
632	for (i=0;i<2;i++) {
633		if (XBIOS_screensmem[i]!=NULL) {
634			if ((XBIOS_cvdo>>16) == VDO_MILAN) {
635				if (i==1) {
636					VsetScreen(-1, -1, MI_MAGIC, CMD_FREEPAGE);
637				}
638			} else {
639				Mfree(XBIOS_screensmem[i]);
640			}
641			XBIOS_screensmem[i]=NULL;
642		}
643	}
644
645	if (XBIOS_shadowscreen!=NULL) {
646		Mfree(XBIOS_shadowscreen);
647		XBIOS_shadowscreen=NULL;
648	}
649}
650
651static SDL_Surface *XBIOS_SetVideoMode(_THIS, SDL_Surface *current,
652				int width, int height, int bpp, Uint32 flags)
653{
654	int mode, new_depth;
655	int i, num_buffers;
656	xbiosmode_t *new_video_mode;
657	Uint32 new_screen_size;
658	Uint32 modeflags;
659
660	/* Free current buffers */
661	XBIOS_FreeBuffers(this);
662
663	/* Try to set the requested linear video mode */
664	bpp = (bpp+7)/8-1;
665	for ( mode=0; SDL_modelist[bpp][mode]; ++mode ) {
666		if ( (SDL_modelist[bpp][mode]->w == width) &&
667		     (SDL_modelist[bpp][mode]->h == height) ) {
668			break;
669		}
670	}
671	if ( SDL_modelist[bpp][mode] == NULL ) {
672		SDL_SetError("Couldn't find requested mode in list");
673		return(NULL);
674	}
675	new_video_mode = SDL_xbiosmode[bpp][mode];
676
677	modeflags = SDL_FULLSCREEN | SDL_PREALLOC;
678
679	/* Allocate needed buffers: simple/double buffer and shadow surface */
680	new_depth = new_video_mode->depth;
681	if (new_depth == 4) {
682		SDL_Atari_C2pConvert = SDL_Atari_C2pConvert4;
683		new_depth=8;
684		modeflags |= SDL_SWSURFACE|SDL_HWPALETTE;
685	} else if (new_depth == 8) {
686		SDL_Atari_C2pConvert = SDL_Atari_C2pConvert8;
687		modeflags |= SDL_SWSURFACE|SDL_HWPALETTE;
688	} else {
689		modeflags |= SDL_HWSURFACE;
690	}
691
692	new_screen_size = width * height * ((new_depth)>>3);
693	new_screen_size += 256; /* To align on a 256 byte adress */
694
695	if (new_video_mode->flags & XBIOSMODE_C2P) {
696		XBIOS_shadowscreen = Atari_SysMalloc(new_screen_size, MX_PREFTTRAM);
697
698		if (XBIOS_shadowscreen == NULL) {
699			SDL_SetError("Can not allocate %d KB for shadow buffer", new_screen_size>>10);
700			return (NULL);
701		}
702		SDL_memset(XBIOS_shadowscreen, 0, new_screen_size);
703	}
704
705	/* Output buffer needs to be twice in size for the software double-line mode */
706	if (new_video_mode->flags & XBIOSMODE_DOUBLELINE) {
707		new_screen_size <<= 1;
708	}
709
710	/* Double buffer ? */
711	num_buffers = 1;
712
713#if SDL_VIDEO_OPENGL
714	if (flags & SDL_OPENGL) {
715		if (this->gl_config.double_buffer) {
716			flags |= SDL_DOUBLEBUF;
717		}
718	}
719#endif
720	if ((flags & SDL_DOUBLEBUF) && ((XBIOS_cvdo>>16) != VDO_MILAN)) {
721		num_buffers = 2;
722		modeflags |= SDL_DOUBLEBUF;
723	}
724
725	/* Allocate buffers */
726	for (i=0; i<num_buffers; i++) {
727		if ((XBIOS_cvdo>>16) == VDO_MILAN) {
728			if (i==0) {
729				XBIOS_screensmem[i] = XBIOS_oldvbase;
730			} else {
731				VsetScreen(-1, &XBIOS_screensmem[i], MI_MAGIC, CMD_ALLOCPAGE);
732			}
733		} else {
734			XBIOS_screensmem[i] = Atari_SysMalloc(new_screen_size, MX_STRAM);
735		}
736
737		if (XBIOS_screensmem[i]==NULL) {
738			XBIOS_FreeBuffers(this);
739			SDL_SetError("Can not allocate %d KB for buffer %d", new_screen_size>>10, i);
740			return (NULL);
741		}
742		SDL_memset(XBIOS_screensmem[i], 0, new_screen_size);
743
744		XBIOS_screens[i]=(void *) (( (long) XBIOS_screensmem[i]+256) & 0xFFFFFF00UL);
745	}
746
747	/* Allocate the new pixel format for the screen */
748	if ( ! SDL_ReallocFormat(current, new_depth, 0, 0, 0, 0) ) {
749		XBIOS_FreeBuffers(this);
750		SDL_SetError("Couldn't allocate new pixel format for requested mode");
751		return(NULL);
752	}
753
754	XBIOS_current = new_video_mode;
755	current->w = width;
756	current->h = height;
757	current->pitch = (width * new_depth)>>3;
758
759	/* this is for C2P conversion */
760	XBIOS_pitch = (new_video_mode->width * new_video_mode->depth)>>3;
761
762	if (new_video_mode->flags & XBIOSMODE_C2P)
763		current->pixels = XBIOS_shadowscreen;
764	else
765		current->pixels = XBIOS_screens[0];
766
767	XBIOS_fbnum = 0;
768
769#if SDL_VIDEO_OPENGL
770	if (flags & SDL_OPENGL) {
771		if (!SDL_AtariGL_Init(this, current)) {
772			XBIOS_FreeBuffers(this);
773			SDL_SetError("Can not create OpenGL context");
774			return NULL;
775		}
776
777		modeflags |= SDL_OPENGL;
778	}
779#endif
780
781	current->flags = modeflags;
782
783#ifndef DEBUG_VIDEO_XBIOS
784	/* Now set the video mode */
785	if ((XBIOS_cvdo>>16) == VDO_MILAN) {
786		VsetScreen(-1, XBIOS_screens[0], MI_MAGIC, CMD_SETADR);
787	} else {
788		Setscreen(-1,XBIOS_screens[0],-1);
789	}
790
791	switch(XBIOS_cvdo >> 16) {
792		case VDO_ST:
793			Setscreen(-1,-1,new_video_mode->number);
794
795			/* Reset palette */
796			for (i=0;i<16;i++) {
797				TT_palette[i]= ((i>>1)<<8) | (((i*8)/17)<<4) | (i>>1);
798			}
799			Setpalette(TT_palette);
800			break;
801		case VDO_STE:
802			Setscreen(-1,-1,new_video_mode->number);
803
804			/* Reset palette */
805			for (i=0;i<16;i++)
806			{
807				int c;
808
809				c=((i&1)<<3)|((i>>1)&7);
810				TT_palette[i]=(c<<8)|(c<<4)|c;
811			}
812			Setpalette(TT_palette);
813			break;
814		case VDO_TT:
815			EsetShift(new_video_mode->number);
816			break;
817		case VDO_F30:
818			if (XBIOS_centscreen) {
819				SDL_XBIOS_CentscreenSetmode(this, width, height, new_depth);
820			} else {
821				VsetMode(new_video_mode->number);
822			}
823
824			/* Set hardware palette to black in True Colour */
825			if (new_depth > 8) {
826				SDL_memset(F30_palette, 0, sizeof(F30_palette));
827				VsetRGB(0,256,F30_palette);
828			}
829			break;
830		case VDO_MILAN:
831			VsetScreen(-1, new_video_mode->number, MI_MAGIC, CMD_SETMODE);
832
833			/* Set hardware palette to black in True Colour */
834			if (new_depth > 8) {
835				SDL_memset(F30_palette, 0, sizeof(F30_palette));
836				VsetRGB(0,256,F30_palette);
837			}
838			break;
839	}
840
841	Vsync();
842#endif
843
844	this->UpdateRects = XBIOS_UpdateRects;
845
846	return (current);
847}
848
849/* We don't actually allow hardware surfaces other than the main one */
850static int XBIOS_AllocHWSurface(_THIS, SDL_Surface *surface)
851{
852	return(-1);
853}
854
855static void XBIOS_FreeHWSurface(_THIS, SDL_Surface *surface)
856{
857	return;
858}
859
860static int XBIOS_LockHWSurface(_THIS, SDL_Surface *surface)
861{
862	return(0);
863}
864
865static void XBIOS_UnlockHWSurface(_THIS, SDL_Surface *surface)
866{
867	return;
868}
869
870static void XBIOS_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
871{
872	SDL_Surface *surface;
873
874	surface = this->screen;
875
876	if (XBIOS_current->flags & XBIOSMODE_C2P) {
877		int i;
878		int doubleline = (XBIOS_current->flags & XBIOSMODE_DOUBLELINE ? 1 : 0);
879
880		for (i=0;i<numrects;i++) {
881			void *source,*destination;
882			int x1,x2;
883
884			x1 = rects[i].x & ~15;
885			x2 = rects[i].x+rects[i].w;
886			if (x2 & 15) {
887				x2 = (x2 | 15) +1;
888			}
889
890			source = surface->pixels;
891			source += surface->pitch * rects[i].y;
892			source += x1;
893
894			destination = XBIOS_screens[XBIOS_fbnum];
895			destination += XBIOS_pitch * rects[i].y;
896			destination += x1;
897
898			/* Convert chunky to planar screen */
899			SDL_Atari_C2pConvert(
900				source,
901				destination,
902				x2-x1,
903				rects[i].h,
904				doubleline,
905				surface->pitch,
906				XBIOS_pitch
907			);
908		}
909	}
910
911#ifndef DEBUG_VIDEO_XBIOS
912	if ((XBIOS_cvdo>>16) == VDO_MILAN) {
913		VsetScreen(-1, XBIOS_screens[XBIOS_fbnum], MI_MAGIC, CMD_SETADR);
914	} else {
915		Setscreen(-1,XBIOS_screens[XBIOS_fbnum],-1);
916	}
917
918	Vsync();
919#endif
920
921	if ((surface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) {
922		XBIOS_fbnum ^= 1;
923		if ((XBIOS_current->flags & XBIOSMODE_C2P) == 0) {
924			surface->pixels=XBIOS_screens[XBIOS_fbnum];
925		}
926	}
927}
928
929static int XBIOS_FlipHWSurface(_THIS, SDL_Surface *surface)
930{
931	if (XBIOS_current->flags & XBIOSMODE_C2P) {
932		void *destscr;
933		int destx;
934		int doubleline = (XBIOS_current->flags & XBIOSMODE_DOUBLELINE ? 1 : 0);
935
936		/* Center on destination screen */
937		destscr = XBIOS_screens[XBIOS_fbnum];
938		destscr += XBIOS_pitch * ((XBIOS_current->height - surface->h) >> 1);
939		destx = (XBIOS_current->width - surface->w) >> 1;
940		destx &= ~15;
941		destscr += destx;
942
943		/* Convert chunky to planar screen */
944		SDL_Atari_C2pConvert(
945			surface->pixels,
946			destscr,
947			surface->w,
948			surface->h,
949			doubleline,
950			surface->pitch,
951			XBIOS_pitch
952		);
953	}
954
955#ifndef DEBUG_VIDEO_XBIOS
956	if ((XBIOS_cvdo>>16) == VDO_MILAN) {
957		VsetScreen(-1, XBIOS_screens[XBIOS_fbnum], MI_MAGIC, CMD_SETADR);
958	} else {
959		Setscreen(-1,XBIOS_screens[XBIOS_fbnum],-1);
960	}
961
962	Vsync();
963#endif
964
965	if ((surface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) {
966		XBIOS_fbnum ^= 1;
967		if ((XBIOS_current->flags & XBIOSMODE_C2P) == 0) {
968			surface->pixels=XBIOS_screens[XBIOS_fbnum];
969		}
970	}
971
972	return(0);
973}
974
975static int XBIOS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
976{
977#ifndef DEBUG_VIDEO_XBIOS
978	int		i;
979	int		r,v,b;
980
981	switch( XBIOS_cvdo >> 16) {
982		case VDO_ST:
983		case VDO_STE:
984		 	for (i=0;i<ncolors;i++)
985			{
986				r = colors[i].r;
987				v = colors[i].g;
988				b = colors[i].b;
989
990				TT_palette[firstcolor+i]=((r*30)+(v*59)+(b*11))/100;
991			}
992			SDL_Atari_C2pConvert4_pal(TT_palette); /* convert the lighting */
993			break;
994		case VDO_TT:
995			for(i = 0; i < ncolors; i++)
996			{
997				r = colors[i].r;
998				v = colors[i].g;
999				b = colors[i].b;
1000
1001				TT_palette[i]=((r>>4)<<8)|((v>>4)<<4)|(b>>4);
1002			}
1003			EsetPalette(firstcolor,ncolors,TT_palette);
1004			break;
1005		case VDO_F30:
1006		case VDO_MILAN:
1007			for(i = 0; i < ncolors; i++)
1008			{
1009				r = colors[i].r;
1010				v = colors[i].g;
1011				b = colors[i].b;
1012
1013				F30_palette[i]=(r<<16)|(v<<8)|b;
1014			}
1015			VsetRGB(firstcolor,ncolors,F30_palette);
1016			break;
1017	}
1018#endif
1019
1020	return(1);
1021}
1022
1023/* Note:  If we are terminated, this could be called in the middle of
1024   another SDL video routine -- notably UpdateRects.
1025*/
1026static void XBIOS_VideoQuit(_THIS)
1027{
1028	int i,j;
1029
1030	Atari_ShutdownEvents();
1031
1032	/* Restore video mode and palette */
1033#ifndef DEBUG_VIDEO_XBIOS
1034	switch(XBIOS_cvdo >> 16) {
1035		case VDO_ST:
1036		case VDO_STE:
1037			Setscreen(-1,XBIOS_oldvbase,XBIOS_oldvmode);
1038			if (XBIOS_oldnumcol) {
1039				Setpalette(XBIOS_oldpalette);
1040			}
1041			break;
1042		case VDO_TT:
1043			Setscreen(-1,XBIOS_oldvbase,-1);
1044			EsetShift(XBIOS_oldvmode);
1045			if (XBIOS_oldnumcol) {
1046				EsetPalette(0, XBIOS_oldnumcol, XBIOS_oldpalette);
1047			}
1048			break;
1049		case VDO_F30:
1050			Setscreen(-1, XBIOS_oldvbase, -1);
1051			if (XBIOS_centscreen) {
1052				SDL_XBIOS_CentscreenRestore(this, XBIOS_oldvmode);
1053			} else {
1054				VsetMode(XBIOS_oldvmode);
1055			}
1056			if (XBIOS_oldnumcol) {
1057				VsetRGB(0, XBIOS_oldnumcol, XBIOS_oldpalette);
1058			}
1059			break;
1060		case VDO_MILAN:
1061			VsetScreen(-1, &XBIOS_oldvbase, MI_MAGIC, CMD_SETADR);
1062			VsetScreen(-1, &XBIOS_oldvmode, MI_MAGIC, CMD_SETMODE);
1063			if (XBIOS_oldnumcol) {
1064				VsetRGB(0, XBIOS_oldnumcol, XBIOS_oldpalette);
1065			}
1066			break;
1067	}
1068	Vsync();
1069#endif
1070
1071#if SDL_VIDEO_OPENGL
1072	if (gl_active) {
1073		SDL_AtariGL_Quit(this, SDL_TRUE);
1074	}
1075#endif
1076
1077	if (XBIOS_oldpalette) {
1078		SDL_free(XBIOS_oldpalette);
1079		XBIOS_oldpalette=NULL;
1080	}
1081	XBIOS_FreeBuffers(this);
1082
1083	/* Free mode list */
1084	for ( i=0; i<NUM_MODELISTS; ++i ) {
1085		if ( SDL_modelist[i] != NULL ) {
1086			for ( j=0; SDL_modelist[i][j]; ++j )
1087				SDL_free(SDL_modelist[i][j]);
1088			SDL_free(SDL_modelist[i]);
1089			SDL_modelist[i] = NULL;
1090		}
1091		if ( SDL_xbiosmode[i] != NULL ) {
1092			for ( j=0; SDL_xbiosmode[i][j]; ++j )
1093				SDL_free(SDL_xbiosmode[i][j]);
1094			SDL_free(SDL_xbiosmode[i]);
1095			SDL_xbiosmode[i] = NULL;
1096		}
1097	}
1098
1099	this->screen->pixels = NULL;
1100
1101	/* Restore screensavers */
1102	if (SDL_XBIOS_TveillePresent(this)) {
1103		SDL_XBIOS_TveilleEnable(this);
1104	}
1105}
1106
1107#if SDL_VIDEO_OPENGL
1108
1109static void XBIOS_GL_SwapBuffers(_THIS)
1110{
1111	SDL_AtariGL_SwapBuffers(this);
1112	XBIOS_FlipHWSurface(this, this->screen);
1113	SDL_AtariGL_MakeCurrent(this);
1114}
1115
1116#endif
1117