1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2006 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
54#define XBIOS_VID_DRIVER_NAME "xbios"
55
56/* Debug print info */
57#if 0
58#define DEBUG_PRINT(what) \
59	{ \
60		printf what; \
61	}
62#define DEBUG_VIDEO_XBIOS 1
63#else
64#define DEBUG_PRINT(what)
65#undef DEBUG_VIDEO_XBIOS
66#endif
67
68/* Initialization/Query functions */
69static int XBIOS_VideoInit(_THIS, SDL_PixelFormat *vformat);
70static SDL_Rect **XBIOS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
71static SDL_Surface *XBIOS_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
72static int XBIOS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
73static void XBIOS_VideoQuit(_THIS);
74
75/* Hardware surface functions */
76static int XBIOS_AllocHWSurface(_THIS, SDL_Surface *surface);
77static int XBIOS_LockHWSurface(_THIS, SDL_Surface *surface);
78static int XBIOS_FlipHWSurface(_THIS, SDL_Surface *surface);
79static void XBIOS_UnlockHWSurface(_THIS, SDL_Surface *surface);
80static void XBIOS_FreeHWSurface(_THIS, SDL_Surface *surface);
81static void XBIOS_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
82
83#if SDL_VIDEO_OPENGL
84/* OpenGL functions */
85static void XBIOS_GL_SwapBuffers(_THIS);
86#endif
87
88/* To setup palette */
89
90static unsigned short	TT_palette[256];
91static unsigned long	F30_palette[256];
92
93/* Xbios driver bootstrap functions */
94
95static int XBIOS_Available(void)
96{
97	unsigned long cookie_vdo, cookie_mil, cookie_hade, cookie_scpn;
98
99	/* Milan/Hades Atari clones do not have an Atari video chip */
100	if ( (Getcookie(C__MIL, &cookie_mil) == C_FOUND) ||
101		(Getcookie(C_hade, &cookie_hade) == C_FOUND) ) {
102		return 0;
103	}
104
105	/* Cookie _VDO present ? if not, assume ST machine */
106	if (Getcookie(C__VDO, &cookie_vdo) != C_FOUND) {
107		cookie_vdo = VDO_ST << 16;
108	}
109
110	/* Test if we have a monochrome monitor plugged in */
111	switch( cookie_vdo >>16) {
112		case VDO_ST:
113		case VDO_STE:
114			if ( Getrez() == (ST_HIGH>>8) )
115				return 0;
116			break;
117		case VDO_TT:
118			if ( (EgetShift() & ES_MODE) == TT_HIGH)
119				return 0;
120			break;
121		case VDO_F30:
122			if ( VgetMonitor() == MONITOR_MONO)
123				return 0;
124			if (Getcookie(C_SCPN, &cookie_scpn) == C_FOUND) {
125				if (!SDL_XBIOS_SB3Usable((scpn_cookie_t *)cookie_scpn)) {
126					return 0;
127				}
128			}
129			break;
130		default:
131			return 0;
132	}
133
134	return 1;
135}
136
137static void XBIOS_DeleteDevice(SDL_VideoDevice *device)
138{
139	SDL_free(device->hidden);
140	SDL_free(device);
141}
142
143static SDL_VideoDevice *XBIOS_CreateDevice(int devindex)
144{
145	SDL_VideoDevice *device;
146
147	/* Initialize all variables that we clean on shutdown */
148	device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
149	if ( device ) {
150		SDL_memset(device, 0, (sizeof *device));
151		device->hidden = (struct SDL_PrivateVideoData *)
152				SDL_malloc((sizeof *device->hidden));
153		device->gl_data = (struct SDL_PrivateGLData *)
154				SDL_malloc((sizeof *device->gl_data));
155	}
156	if ( (device == NULL) || (device->hidden == NULL) ) {
157		SDL_OutOfMemory();
158		if ( device ) {
159			SDL_free(device);
160		}
161		return(0);
162	}
163	SDL_memset(device->hidden, 0, (sizeof *device->hidden));
164	SDL_memset(device->gl_data, 0, sizeof(*device->gl_data));
165
166	/* Video functions */
167	device->VideoInit = XBIOS_VideoInit;
168	device->ListModes = XBIOS_ListModes;
169	device->SetVideoMode = XBIOS_SetVideoMode;
170	device->SetColors = XBIOS_SetColors;
171	device->UpdateRects = NULL;
172	device->VideoQuit = XBIOS_VideoQuit;
173	device->AllocHWSurface = XBIOS_AllocHWSurface;
174	device->LockHWSurface = XBIOS_LockHWSurface;
175	device->UnlockHWSurface = XBIOS_UnlockHWSurface;
176	device->FlipHWSurface = XBIOS_FlipHWSurface;
177	device->FreeHWSurface = XBIOS_FreeHWSurface;
178
179#if SDL_VIDEO_OPENGL
180	/* OpenGL functions */
181	device->GL_LoadLibrary = SDL_AtariGL_LoadLibrary;
182	device->GL_GetProcAddress = SDL_AtariGL_GetProcAddress;
183	device->GL_GetAttribute = SDL_AtariGL_GetAttribute;
184	device->GL_MakeCurrent = SDL_AtariGL_MakeCurrent;
185	device->GL_SwapBuffers = XBIOS_GL_SwapBuffers;
186#endif
187
188	/* Events */
189	device->InitOSKeymap = Atari_InitOSKeymap;
190	device->PumpEvents = Atari_PumpEvents;
191
192	device->free = XBIOS_DeleteDevice;
193
194	return device;
195}
196
197VideoBootStrap XBIOS_bootstrap = {
198	XBIOS_VID_DRIVER_NAME, "Atari Xbios driver",
199	XBIOS_Available, XBIOS_CreateDevice
200};
201
202void SDL_XBIOS_AddMode(_THIS, Uint16 modecode, Uint16 width, Uint16 height,
203	Uint16 depth, SDL_bool flags)
204{
205	int i, curpos;
206	xbiosmode_t *current_mode;
207
208	/* Check if mode already exists */
209	if (XBIOS_modelist) {
210		current_mode = XBIOS_modelist;
211		for (i=0;i<XBIOS_nummodes; i++, current_mode++) {
212			if (current_mode->width != width)
213				continue;
214			if (current_mode->height != height)
215				continue;
216			if (current_mode->depth != depth)
217				continue;
218			return;
219		}
220	}
221
222	++XBIOS_nummodes;
223	XBIOS_modelist = (xbiosmode_t *) SDL_realloc(XBIOS_modelist, XBIOS_nummodes * sizeof(xbiosmode_t));
224
225	/* Keep the list sorted: bpp, width, height */
226	curpos=0;
227
228	for(i=0; i<XBIOS_nummodes-1; i++) {
229		if (XBIOS_modelist[i].depth <= depth) {
230			if (XBIOS_modelist[i].width < width) {
231				break;
232			} else if (XBIOS_modelist[i].width == width) {
233				if (XBIOS_modelist[i].height <= height) {
234					break;
235				}
236			}
237		}
238		curpos++;
239	}
240
241	/* Push remaining modes further */
242	for(i=XBIOS_nummodes-1; i>curpos; i--) {
243		SDL_memcpy(&XBIOS_modelist[i], &XBIOS_modelist[i-1], sizeof(xbiosmode_t));
244	}
245
246	XBIOS_modelist[curpos].number = modecode;
247	XBIOS_modelist[curpos].width = width;
248	XBIOS_modelist[curpos].height = height;
249	XBIOS_modelist[curpos].depth = depth;
250	XBIOS_modelist[curpos].doubleline = flags;
251}
252
253static int XBIOS_VideoInit(_THIS, SDL_PixelFormat *vformat)
254{
255	int i,j8,j16;
256	xbiosmode_t *current_mode;
257	unsigned long cookie_blow, cookie_scpn, cookie_cnts;
258
259	/* Initialize all variables that we clean on shutdown */
260	memset (SDL_modelist, 0, sizeof(SDL_modelist));
261
262	/* Cookie _VDO present ? if not, assume ST machine */
263	if (Getcookie(C__VDO, &XBIOS_cvdo) != C_FOUND) {
264		XBIOS_cvdo = VDO_ST << 16;
265	}
266
267	/* Allocate memory for old palette */
268	XBIOS_oldpalette = (void *)SDL_malloc(256*sizeof(long));
269	if ( !XBIOS_oldpalette ) {
270		SDL_SetError("Unable to allocate memory for old palette\n");
271		return(-1);
272	}
273
274	/* Initialize video mode list */
275	/* and save current screen status (palette, screen address, video mode) */
276	XBIOS_nummodes = 0;
277	XBIOS_modelist = NULL;
278	XBIOS_centscreen = SDL_FALSE;
279
280	switch (XBIOS_cvdo >>16) {
281		case VDO_ST:
282		case VDO_STE:
283			{
284				short *oldpalette;
285
286				SDL_XBIOS_AddMode(this, ST_LOW>>8,320,200,4,SDL_FALSE);
287
288				XBIOS_oldvbase=Physbase();
289				XBIOS_oldvmode=Getrez();
290				switch(XBIOS_oldvmode << 8) {
291					case ST_LOW:
292						XBIOS_oldnumcol=16;
293						break;
294					case ST_MED:
295						XBIOS_oldnumcol=4;
296						break;
297					case ST_HIGH:
298						XBIOS_oldnumcol=2;
299						break;
300					default:
301						XBIOS_oldnumcol=0;
302						break;
303				}
304
305				oldpalette= (short *) XBIOS_oldpalette;
306				for (i=0;i<XBIOS_oldnumcol;i++) {
307					*oldpalette++=Setcolor(i,-1);
308				}
309
310				vformat->BitsPerPixel = 8;
311			}
312			break;
313		case VDO_TT:
314
315			SDL_XBIOS_AddMode(this, TT_LOW,320,480,8,SDL_FALSE);
316			/* Software double-lined mode */
317			SDL_XBIOS_AddMode(this, TT_LOW,320,240,8,SDL_TRUE);
318
319			XBIOS_oldvbase=Logbase();
320			XBIOS_oldvmode=EgetShift();
321
322			switch(XBIOS_oldvmode & ES_MODE) {
323				case TT_LOW:
324					XBIOS_oldnumcol=256;
325					break;
326				case ST_LOW:
327				case TT_MED:
328					XBIOS_oldnumcol=16;
329					break;
330				case ST_MED:
331					XBIOS_oldnumcol=4;
332					break;
333				case ST_HIGH:
334				case TT_HIGH:
335					XBIOS_oldnumcol=2;
336					break;
337				default:
338					XBIOS_oldnumcol=0;
339					break;
340			}
341			if (XBIOS_oldnumcol) {
342				EgetPalette(0, XBIOS_oldnumcol, XBIOS_oldpalette);
343			}
344
345			vformat->BitsPerPixel = 8;
346			break;
347		case VDO_F30:
348			switch (VgetMonitor())
349			{
350				case MONITOR_MONO:
351					/* Not usable */
352					break;
353				case MONITOR_RGB:
354				case MONITOR_TV:
355					SDL_XBIOS_AddMode(this, BPS16|COL80|OVERSCAN|VERTFLAG,768,480,16,SDL_FALSE);
356					SDL_XBIOS_AddMode(this, BPS16|COL80|OVERSCAN,768,240,16,SDL_FALSE);
357					SDL_XBIOS_AddMode(this, BPS16|COL80|VERTFLAG,640,400,16,SDL_FALSE);
358					SDL_XBIOS_AddMode(this, BPS16|COL80,640,200,16,SDL_FALSE);
359					SDL_XBIOS_AddMode(this, BPS16|OVERSCAN|VERTFLAG,384,480,16,SDL_FALSE);
360					SDL_XBIOS_AddMode(this, BPS16|OVERSCAN,384,240,16,SDL_FALSE);
361					SDL_XBIOS_AddMode(this, BPS16|VERTFLAG,320,400,16,SDL_FALSE);
362					SDL_XBIOS_AddMode(this, BPS16,320,200,16,SDL_FALSE);
363					SDL_XBIOS_AddMode(this, BPS8|COL80|OVERSCAN|VERTFLAG,768,480,8,SDL_FALSE);
364					SDL_XBIOS_AddMode(this, BPS8|COL80|OVERSCAN,768,240,8,SDL_FALSE);
365					SDL_XBIOS_AddMode(this, BPS8|COL80|VERTFLAG,640,400,8,SDL_FALSE);
366					SDL_XBIOS_AddMode(this, BPS8|COL80,640,200,8,SDL_FALSE);
367					SDL_XBIOS_AddMode(this, BPS8|OVERSCAN|VERTFLAG,384,480,8,SDL_FALSE);
368					SDL_XBIOS_AddMode(this, BPS8|OVERSCAN,384,240,8,SDL_FALSE);
369					SDL_XBIOS_AddMode(this, BPS8|VERTFLAG,320,400,8,SDL_FALSE);
370					SDL_XBIOS_AddMode(this, BPS8,320,200,8,SDL_FALSE);
371					break;
372				case MONITOR_VGA:
373					SDL_XBIOS_AddMode(this, BPS16,320,480,16,SDL_FALSE);
374					SDL_XBIOS_AddMode(this, BPS16|VERTFLAG,320,240,16,SDL_FALSE);
375					SDL_XBIOS_AddMode(this, BPS8|COL80,640,480,8,SDL_FALSE);
376					SDL_XBIOS_AddMode(this, BPS8|COL80|VERTFLAG,640,240,8,SDL_FALSE);
377					SDL_XBIOS_AddMode(this, BPS8,320,480,8,SDL_FALSE);
378					SDL_XBIOS_AddMode(this, BPS8|VERTFLAG,320,240,8,SDL_FALSE);
379					break;
380			}
381			XBIOS_oldvbase=Logbase();
382			XBIOS_oldvmode=VsetMode(-1);
383
384			XBIOS_oldnumcol= 1<< (1 << (XBIOS_oldvmode & NUMCOLS));
385			if (XBIOS_oldnumcol > 256) {
386				XBIOS_oldnumcol = 0;
387			}
388			if (XBIOS_oldnumcol) {
389				VgetRGB(0, XBIOS_oldnumcol, XBIOS_oldpalette);
390			}
391
392			vformat->BitsPerPixel = 16;
393
394			/* Keep vga/rvb, and pal/ntsc bits */
395			current_mode = XBIOS_modelist;
396			for (i=0;i<XBIOS_nummodes;i++) {
397				Uint16 newvmode;
398
399				newvmode = current_mode->number;
400				newvmode &= ~(VGA|PAL);
401				newvmode |= XBIOS_oldvmode & (VGA|PAL);
402				current_mode->number = newvmode;
403
404				current_mode++;
405			}
406
407			/* Initialize BlowUp/SB3/Centscreen stuff if present */
408			if (Getcookie(C_BLOW, &cookie_blow) == C_FOUND) {
409				SDL_XBIOS_BlowupInit(this, (blow_cookie_t *)cookie_blow);
410			} else if (Getcookie(C_SCPN, &cookie_scpn) == C_FOUND) {
411				SDL_XBIOS_SB3Init(this, (scpn_cookie_t *)cookie_scpn);
412			} else if (Getcookie(C_CNTS, &cookie_cnts) == C_FOUND) {
413				XBIOS_oldvmode = SDL_XBIOS_CentscreenInit(this);
414				XBIOS_centscreen = SDL_TRUE;
415			}
416
417			break;
418	}
419
420	/* Determine the current screen size */
421	if ( XBIOS_nummodes > 0 ) {
422		/* FIXME: parse video mode list to search for current mode */
423		this->info.current_w = XBIOS_modelist[0].width;
424		this->info.current_h = XBIOS_modelist[0].height;
425	}
426
427	current_mode = XBIOS_modelist;
428	j8 = j16 = 0;
429	for (i=0; i<XBIOS_nummodes; i++, current_mode++) {
430		switch (current_mode->depth) {
431			case 4:
432			case 8:
433				SDL_modelist[0][j8] = SDL_malloc(sizeof(SDL_Rect));
434				SDL_modelist[0][j8]->x = SDL_modelist[0][j8]->y = 0;
435				SDL_modelist[0][j8]->w = current_mode->width;
436				SDL_modelist[0][j8]->h = current_mode->height;
437				XBIOS_videomodes[0][j8]=current_mode;
438				j8++;
439				break;
440			case 16:
441				SDL_modelist[1][j16] = SDL_malloc(sizeof(SDL_Rect));
442				SDL_modelist[1][j16]->x = SDL_modelist[1][j16]->y = 0;
443				SDL_modelist[1][j16]->w = current_mode->width;
444				SDL_modelist[1][j16]->h = current_mode->height;
445				XBIOS_videomodes[1][j16]=current_mode;
446				j16++;
447				break;
448		}
449	}
450	SDL_modelist[0][j8] = NULL;
451	SDL_modelist[1][j16] = NULL;
452
453	XBIOS_screens[0]=NULL;
454	XBIOS_screens[1]=NULL;
455	XBIOS_shadowscreen=NULL;
456
457	/* Update hardware info */
458	this->info.hw_available = 1;
459	this->info.video_mem = (Uint32) Atari_SysMalloc(-1L, MX_STRAM);
460
461	/* Init chunky to planar routine */
462	SDL_Atari_C2pConvert = SDL_Atari_C2pConvert8;
463
464#if SDL_VIDEO_OPENGL
465	SDL_AtariGL_InitPointers(this);
466#endif
467
468	/* Disable screensavers */
469	if (SDL_XBIOS_TveillePresent(this)) {
470		SDL_XBIOS_TveilleDisable(this);
471	}
472
473	/* We're done! */
474	return(0);
475}
476
477static SDL_Rect **XBIOS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
478{
479	/* 8 bits -> list 0 */
480	/* 16 bits -> list 1 */
481	if ((format->BitsPerPixel != 8) && (format->BitsPerPixel !=16)) {
482		return NULL;
483	}
484
485	return(SDL_modelist[(format->BitsPerPixel)>>4]);
486}
487
488static void XBIOS_FreeBuffers(_THIS)
489{
490	int i;
491
492	for (i=0;i<2;i++) {
493		if (XBIOS_screensmem[i]!=NULL) {
494			Mfree(XBIOS_screensmem[i]);
495			XBIOS_screensmem[i]=NULL;
496		}
497	}
498
499	if (XBIOS_shadowscreen!=NULL) {
500		Mfree(XBIOS_shadowscreen);
501		XBIOS_shadowscreen=NULL;
502	}
503}
504
505static SDL_Surface *XBIOS_SetVideoMode(_THIS, SDL_Surface *current,
506				int width, int height, int bpp, Uint32 flags)
507{
508	int mode, new_depth;
509	int i;
510	xbiosmode_t *new_video_mode;
511	Uint32 new_screen_size;
512	Uint32 modeflags;
513
514	/* Free current buffers */
515	XBIOS_FreeBuffers(this);
516
517	/* Limit bpp */
518	if (bpp>16) {
519		bpp = 16;
520	}
521	bpp >>= 4;
522
523	/* Search if the mode exists (width, height, bpp) */
524	for ( mode=0; SDL_modelist[bpp][mode]; ++mode ) {
525		if ( (SDL_modelist[bpp][mode]->w == width) &&
526		     (SDL_modelist[bpp][mode]->h == height) ) {
527
528			break;
529		}
530	}
531	if ( SDL_modelist[bpp][mode] == NULL ) {
532		SDL_SetError("Couldn't find requested mode in list");
533		return(NULL);
534	}
535
536	modeflags = SDL_FULLSCREEN | SDL_PREALLOC;
537
538	/* Allocate needed buffers: simple/double buffer and shadow surface */
539	new_video_mode = XBIOS_videomodes[bpp][mode];
540	new_depth = new_video_mode->depth;
541	if (new_depth == 4) {
542		SDL_Atari_C2pConvert = SDL_Atari_C2pConvert4;
543		new_depth=8;
544		modeflags |= SDL_SWSURFACE|SDL_HWPALETTE;
545	} else if (new_depth == 8) {
546		SDL_Atari_C2pConvert = SDL_Atari_C2pConvert8;
547		modeflags |= SDL_SWSURFACE|SDL_HWPALETTE;
548	} else {
549		modeflags |= SDL_HWSURFACE;
550	}
551
552	new_screen_size = width * height * ((new_depth)>>3);
553	new_screen_size += 256; /* To align on a 256 byte adress */
554
555	if (new_depth == 8) {
556		XBIOS_shadowscreen = Atari_SysMalloc(new_screen_size, MX_PREFTTRAM);
557
558		if (XBIOS_shadowscreen == NULL) {
559			SDL_SetError("Can not allocate %d KB for shadow buffer", new_screen_size>>10);
560			return (NULL);
561		}
562		SDL_memset(XBIOS_shadowscreen, 0, new_screen_size);
563	}
564
565	/* Output buffer needs to be twice in size for the software double-line mode */
566	XBIOS_doubleline = SDL_FALSE;
567	if (new_video_mode->doubleline) {
568		new_screen_size <<= 1;
569		XBIOS_doubleline = SDL_TRUE;
570	}
571
572	XBIOS_screensmem[0] = Atari_SysMalloc(new_screen_size, MX_STRAM);
573
574	if (XBIOS_screensmem[0]==NULL) {
575		XBIOS_FreeBuffers(this);
576		SDL_SetError("Can not allocate %d KB for frame buffer", new_screen_size>>10);
577		return (NULL);
578	}
579	SDL_memset(XBIOS_screensmem[0], 0, new_screen_size);
580
581	XBIOS_screens[0]=(void *) (( (long) XBIOS_screensmem[0]+256) & 0xFFFFFF00UL);
582
583#if SDL_VIDEO_OPENGL
584	if (flags & SDL_OPENGL) {
585		if (this->gl_config.double_buffer) {
586			flags |= SDL_DOUBLEBUF;
587		}
588	}
589#endif
590
591	/* Double buffer ? */
592	if (flags & SDL_DOUBLEBUF) {
593		XBIOS_screensmem[1] = Atari_SysMalloc(new_screen_size, MX_STRAM);
594
595		if (XBIOS_screensmem[1]==NULL) {
596			XBIOS_FreeBuffers(this);
597			SDL_SetError("Can not allocate %d KB for double buffer", new_screen_size>>10);
598			return (NULL);
599		}
600		SDL_memset(XBIOS_screensmem[1], 0, new_screen_size);
601
602		XBIOS_screens[1]=(void *) (( (long) XBIOS_screensmem[1]+256) & 0xFFFFFF00UL);
603		modeflags |= SDL_DOUBLEBUF;
604	}
605
606	/* Allocate the new pixel format for the screen */
607	if ( ! SDL_ReallocFormat(current, new_depth, 0, 0, 0, 0) ) {
608		XBIOS_FreeBuffers(this);
609		SDL_SetError("Couldn't allocate new pixel format for requested mode");
610		return(NULL);
611	}
612
613	current->w = XBIOS_width = width;
614	current->h = XBIOS_height = height;
615	current->pitch = (width * new_depth)>>3;
616
617	/* this is for C2P conversion */
618	XBIOS_pitch = (new_video_mode->width * new_video_mode->depth)>>3;
619
620	if (new_depth == 8)
621		current->pixels = XBIOS_shadowscreen;
622	else
623		current->pixels = XBIOS_screens[0];
624
625	XBIOS_fbnum = 0;
626
627#if SDL_VIDEO_OPENGL
628	if (flags & SDL_OPENGL) {
629		if (!SDL_AtariGL_Init(this, current)) {
630			XBIOS_FreeBuffers(this);
631			SDL_SetError("Can not create OpenGL context");
632			return NULL;
633		}
634
635		modeflags |= SDL_OPENGL;
636	}
637#endif
638
639	current->flags = modeflags;
640
641	/* Now set the video mode */
642#ifndef DEBUG_VIDEO_XBIOS
643	Setscreen(-1,XBIOS_screens[0],-1);
644#endif
645
646	switch(XBIOS_cvdo >> 16) {
647		case VDO_ST:
648#ifndef DEBUG_VIDEO_XBIOS
649			Setscreen(-1,-1,new_video_mode->number);
650#endif
651			/* Reset palette */
652			for (i=0;i<16;i++) {
653				TT_palette[i]= ((i>>1)<<8) | (((i*8)/17)<<4) | (i>>1);
654			}
655#ifndef DEBUG_VIDEO_XBIOS
656			Setpalette(TT_palette);
657#endif
658			break;
659		case VDO_STE:
660#ifndef DEBUG_VIDEO_XBIOS
661			Setscreen(-1,-1,new_video_mode->number);
662#endif
663			/* Reset palette */
664			for (i=0;i<16;i++)
665			{
666				int c;
667
668				c=((i&1)<<3)|((i>>1)&7);
669				TT_palette[i]=(c<<8)|(c<<4)|c;
670			}
671#ifndef DEBUG_VIDEO_XBIOS
672			Setpalette(TT_palette);
673#endif
674			break;
675		case VDO_TT:
676#ifndef DEBUG_VIDEO_XBIOS
677			EsetShift(new_video_mode->number);
678#endif
679			break;
680		case VDO_F30:
681#ifndef DEBUG_VIDEO_XBIOS
682			if (XBIOS_centscreen) {
683				SDL_XBIOS_CentscreenSetmode(this, width, height, new_depth);
684			} else {
685				VsetMode(new_video_mode->number);
686			}
687#endif
688			/* Set hardware palette to black in True Colour */
689			if (new_depth == 16) {
690				SDL_memset(F30_palette, 0, sizeof(F30_palette));
691				VsetRGB(0,256,F30_palette);
692			}
693			break;
694	}
695
696	Vsync();
697
698	this->UpdateRects = XBIOS_UpdateRects;
699
700	return (current);
701}
702
703/* We don't actually allow hardware surfaces other than the main one */
704static int XBIOS_AllocHWSurface(_THIS, SDL_Surface *surface)
705{
706	return(-1);
707}
708
709static void XBIOS_FreeHWSurface(_THIS, SDL_Surface *surface)
710{
711	return;
712}
713
714static int XBIOS_LockHWSurface(_THIS, SDL_Surface *surface)
715{
716	return(0);
717}
718
719static void XBIOS_UnlockHWSurface(_THIS, SDL_Surface *surface)
720{
721	return;
722}
723
724static void XBIOS_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
725{
726	SDL_Surface *surface;
727
728	surface = this->screen;
729
730	if ((surface->format->BitsPerPixel) == 8) {
731		int i;
732
733		for (i=0;i<numrects;i++) {
734			void *source,*destination;
735			int x1,x2;
736
737			x1 = rects[i].x & ~15;
738			x2 = rects[i].x+rects[i].w;
739			if (x2 & 15) {
740				x2 = (x2 | 15) +1;
741			}
742
743			source = surface->pixels;
744			source += surface->pitch * rects[i].y;
745			source += x1;
746
747			destination = XBIOS_screens[XBIOS_fbnum];
748			destination += XBIOS_pitch * rects[i].y;
749			destination += x1;
750
751			/* Convert chunky to planar screen */
752			SDL_Atari_C2pConvert(
753				source,
754				destination,
755				x2-x1,
756				rects[i].h,
757				XBIOS_doubleline,
758				surface->pitch,
759				XBIOS_pitch
760			);
761		}
762	}
763
764#ifndef DEBUG_VIDEO_XBIOS
765	Setscreen(-1,XBIOS_screens[XBIOS_fbnum],-1);
766#endif
767	Vsync();
768
769	if ((surface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) {
770		XBIOS_fbnum ^= 1;
771		if ((surface->format->BitsPerPixel) > 8) {
772			surface->pixels=XBIOS_screens[XBIOS_fbnum];
773		}
774	}
775}
776
777static int XBIOS_FlipHWSurface(_THIS, SDL_Surface *surface)
778{
779	if ((surface->format->BitsPerPixel) == 8) {
780		void *destscr;
781		int destx;
782
783		/* Center on destination screen */
784		destscr = XBIOS_screens[XBIOS_fbnum];
785		destscr += XBIOS_pitch * ((XBIOS_height - surface->h) >> 1);
786		destx = (XBIOS_width - surface->w) >> 1;
787		destx &= ~15;
788		destscr += destx;
789
790		/* Convert chunky to planar screen */
791		SDL_Atari_C2pConvert(
792			surface->pixels,
793			destscr,
794			surface->w,
795			surface->h,
796			XBIOS_doubleline,
797			surface->pitch,
798			XBIOS_pitch
799		);
800	}
801
802#ifndef DEBUG_VIDEO_XBIOS
803	Setscreen(-1,XBIOS_screens[XBIOS_fbnum],-1);
804#endif
805	Vsync();
806
807	if ((surface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) {
808		XBIOS_fbnum ^= 1;
809		if ((surface->format->BitsPerPixel) > 8) {
810			surface->pixels=XBIOS_screens[XBIOS_fbnum];
811		}
812	}
813
814	return(0);
815}
816
817static int XBIOS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
818{
819	int		i;
820	int		r,v,b;
821
822	switch( XBIOS_cvdo >> 16) {
823		case VDO_ST:
824		case VDO_STE:
825		 	for (i=0;i<ncolors;i++)
826			{
827				r = colors[i].r;
828				v = colors[i].g;
829				b = colors[i].b;
830
831				TT_palette[firstcolor+i]=((r*30)+(v*59)+(b*11))/100;
832			}
833			SDL_Atari_C2pConvert4_pal(TT_palette); /* convert the lighting */
834			break;
835		case VDO_TT:
836			for(i = 0; i < ncolors; i++)
837			{
838				r = colors[i].r;
839				v = colors[i].g;
840				b = colors[i].b;
841
842				TT_palette[i]=((r>>4)<<8)|((v>>4)<<4)|(b>>4);
843			}
844#ifndef DEBUG_VIDEO_XBIOS
845			EsetPalette(firstcolor,ncolors,TT_palette);
846#endif
847			break;
848		case VDO_F30:
849			for(i = 0; i < ncolors; i++)
850			{
851				r = colors[i].r;
852				v = colors[i].g;
853				b = colors[i].b;
854
855				F30_palette[i]=(r<<16)|(v<<8)|b;
856			}
857#ifndef DEBUG_VIDEO_XBIOS
858			VsetRGB(firstcolor,ncolors,F30_palette);
859#endif
860			break;
861	}
862
863	return(1);
864}
865
866/* Note:  If we are terminated, this could be called in the middle of
867   another SDL video routine -- notably UpdateRects.
868*/
869static void XBIOS_VideoQuit(_THIS)
870{
871	int i,j;
872
873	Atari_ShutdownEvents();
874
875	/* Restore video mode and palette */
876#ifndef DEBUG_VIDEO_XBIOS
877	switch(XBIOS_cvdo >> 16) {
878		case VDO_ST:
879		case VDO_STE:
880			Setscreen(-1,XBIOS_oldvbase,XBIOS_oldvmode);
881			if (XBIOS_oldnumcol) {
882				Setpalette(XBIOS_oldpalette);
883			}
884			break;
885		case VDO_TT:
886			Setscreen(-1,XBIOS_oldvbase,-1);
887			EsetShift(XBIOS_oldvmode);
888			if (XBIOS_oldnumcol) {
889				EsetPalette(0, XBIOS_oldnumcol, XBIOS_oldpalette);
890			}
891			break;
892		case VDO_F30:
893			Setscreen(-1, XBIOS_oldvbase, -1);
894			if (XBIOS_centscreen) {
895				SDL_XBIOS_CentscreenRestore(this, XBIOS_oldvmode);
896			} else {
897				VsetMode(XBIOS_oldvmode);
898			}
899			if (XBIOS_oldnumcol) {
900				VsetRGB(0, XBIOS_oldnumcol, XBIOS_oldpalette);
901			}
902			break;
903	}
904	Vsync();
905#endif
906
907
908#if SDL_VIDEO_OPENGL
909	if (gl_active) {
910		SDL_AtariGL_Quit(this, SDL_TRUE);
911	}
912#endif
913
914	if (XBIOS_oldpalette) {
915		SDL_free(XBIOS_oldpalette);
916		XBIOS_oldpalette=NULL;
917	}
918	XBIOS_FreeBuffers(this);
919
920	/* Free mode list */
921	for (j=0;j<NUM_MODELISTS;j++) {
922		for (i=0;i<SDL_NUMMODES;i++) {
923			if (SDL_modelist[j][i]!=NULL) {
924				SDL_free(SDL_modelist[j][i]);
925				SDL_modelist[j][i]=NULL;
926			}
927		}
928	}
929
930	if (XBIOS_modelist) {
931		SDL_free(XBIOS_modelist);
932		XBIOS_nummodes=0;
933		XBIOS_modelist=NULL;
934	}
935
936	this->screen->pixels = NULL;
937
938	/* Restore screensavers */
939	if (SDL_XBIOS_TveillePresent(this)) {
940		SDL_XBIOS_TveilleRestore(this);
941	}
942}
943
944#if SDL_VIDEO_OPENGL
945
946static void XBIOS_GL_SwapBuffers(_THIS)
947{
948	SDL_AtariGL_SwapBuffers(this);
949	XBIOS_FlipHWSurface(this, this->screen);
950	SDL_AtariGL_MakeCurrent(this);
951}
952
953#endif
954