1 /*
2  * Schism Tracker - a cross-platform Impulse Tracker clone
3  * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
4  * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
5  * copyright (c) 2009 Storlek & Mrs. Brisby
6  * copyright (c) 2010-2012 Storlek
7  * URL: http://schismtracker.org/
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 #define NATIVE_SCREEN_WIDTH             640
24 #define NATIVE_SCREEN_HEIGHT            400
25 
26 /* should be the native res of the display (set once and never again)
27  * assumes the user starts schism from the desktop and that the desktop
28  * is the native res (or at least something with square pixels) */
29 static int display_native_x = -1;
30 static int display_native_y = -1;
31 
32 #include "headers.h"
33 #include "it.h"
34 #include "osdefs.h"
35 
36 /* bugs
37  * ... in sdl. not in this file :)
38  *
39  *  - take special care to call SDL_SetVideoMode _exactly_ once
40  *    when on a console (video.desktop.fb_hacks)
41  *
42  */
43 
44 #if HAVE_SYS_KD_H
45 # include <sys/kd.h>
46 #endif
47 #if HAVE_LINUX_FB_H
48 # include <linux/fb.h>
49 #endif
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #if HAVE_SYS_IOCTL_H
53 # include <sys/ioctl.h>
54 #endif
55 #if HAVE_SIGNAL_H
56 #include <signal.h>
57 #endif
58 
59 /* for memcpy */
60 #include <string.h>
61 #include <stdlib.h>
62 #include <errno.h>
63 #include <stdio.h>
64 
65 #include "sdlmain.h"
66 
67 #include <unistd.h>
68 #include <fcntl.h>
69 
70 #include "video.h"
71 
72 #ifndef MACOSX
73 #ifdef WIN32
74 #include "auto/schismico.h"
75 #else
76 #include "auto/schismico_hires.h"
77 #endif
78 #endif
79 
80 #ifndef APIENTRY
81 #define APIENTRY
82 #endif
83 #ifndef APIENTRYP
84 #define APIENTRYP APIENTRY *
85 #endif
86 
87 extern int macosx_did_finderlaunch;
88 
89 #define NVIDIA_PixelDataRange   1
90 
91 #if !defined(USE_OPENGL)
92 typedef unsigned int GLuint;
93 typedef int GLint;
94 typedef int GLenum;
95 typedef int GLsizei;
96 typedef void GLvoid;
97 typedef float GLfloat;
98 typedef int GLboolean;
99 typedef int GLbitfield;
100 typedef float GLclampf;
101 typedef unsigned char GLubyte;
102 #endif
103 
104 #if USE_OPENGL && NVIDIA_PixelDataRange
105 
106 #ifndef WGL_NV_allocate_memory
107 #define WGL_NV_allocate_memory 1
108 typedef void * (APIENTRY * PFNWGLALLOCATEMEMORYNVPROC)
109 	(int size, float readfreq, float writefreq, float priority);
110 typedef void (APIENTRY * PFNWGLFREEMEMORYNVPROC) (void *pointer);
111 #endif
112 
113 static PFNWGLALLOCATEMEMORYNVPROC db_glAllocateMemoryNV = NULL;
114 static PFNWGLFREEMEMORYNVPROC db_glFreeMemoryNV = NULL;
115 
116 #ifndef GL_NV_pixel_data_range
117 #define GL_NV_pixel_data_range 1
118 #define GL_WRITE_PIXEL_DATA_RANGE_NV      0x8878
119 typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer);
120 typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);
121 #endif
122 
123 static PFNGLPIXELDATARANGENVPROC glPixelDataRangeNV = NULL;
124 
125 #endif
126 
127 /* leeto drawing skills */
128 #define MOUSE_HEIGHT    14
129 static const unsigned int _mouse_pointer[] = {
130 	/* x....... */  0x80,
131 	/* xx...... */  0xc0,
132 	/* xxx..... */  0xe0,
133 	/* xxxx.... */  0xf0,
134 	/* xxxxx... */  0xf8,
135 	/* xxxxxx.. */  0xfc,
136 	/* xxxxxxx. */  0xfe,
137 	/* xxxxxxxx */  0xff,
138 	/* xxxxxxx. */  0xfe,
139 	/* xxxxx... */  0xf8,
140 	/* x...xx.. */  0x8c,
141 	/* ....xx.. */  0x0c,
142 	/* .....xx. */  0x06,
143 	/* .....xx. */  0x06,
144 
145 0,0
146 };
147 
148 
149 #ifdef WIN32
150 #include <windows.h>
151 #include "wine-ddraw.h"
152 struct private_hwdata {
153 	LPDIRECTDRAWSURFACE3 dd_surface;
154 	LPDIRECTDRAWSURFACE3 dd_writebuf;
155 };
156 #endif
157 
158 struct video_cf {
159 	struct {
160 		unsigned int width;
161 		unsigned int height;
162 
163 		int autoscale;
164 	} draw;
165 	struct {
166 		unsigned int width,height,bpp;
167 		int want_fixed;
168 
169 		int swsurface;
170 		int fb_hacks;
171 		int fullscreen;
172 		int doublebuf;
173 		int want_type;
174 		int type;
175 #define VIDEO_SURFACE           0
176 #define VIDEO_DDRAW             1
177 #define VIDEO_YUV               2
178 #define VIDEO_GL                3
179 	} desktop;
180 	struct {
181 		unsigned int pitch;
182 		void * framebuf;
183 		GLuint texture;
184 		GLuint displaylist;
185 		GLint max_texsize;
186 		int bilinear;
187 		int packed_pixel;
188 		int paletted_texture;
189 #if defined(NVIDIA_PixelDataRange)
190 		int pixel_data_range;
191 #endif
192 	} gl;
193 #if defined(WIN32)
194 	struct {
195 		SDL_Surface * surface;
196 		RECT rect;
197 		DDBLTFX fx;
198 	} ddblit;
199 #endif
200 	unsigned int yuvlayout;
201 	SDL_Rect clip;
202 	SDL_Surface * surface;
203 	SDL_Overlay * overlay;
204 	/* to convert 32-bit color to 24-bit color */
205 	unsigned char cv32backing[NATIVE_SCREEN_WIDTH * 8];
206 	/* for tv mode */
207 	unsigned char cv8backing[NATIVE_SCREEN_WIDTH];
208 	struct {
209 		unsigned int x;
210 		unsigned int y;
211 		int visible;
212 	} mouse;
213 
214 	unsigned int yuv_y[256];
215 	unsigned int yuv_u[256];
216 	unsigned int yuv_v[256];
217 
218 	unsigned int pal[256];
219 
220 	unsigned int tc_bgr32[256];
221 };
222 static struct video_cf video;
223 
224 #ifdef USE_OPENGL
int_log2(int val)225 static int int_log2(int val) {
226 	int l = 0;
227 	while ((val >>= 1 ) != 0) l++;
228 	return l;
229 }
230 #endif
231 
232 #ifdef MACOSX
233 #include <OpenGL/gl.h>
234 #include <OpenGL/glu.h>
235 #include <OpenGL/glext.h>
236 
237 /* opengl is EVERYWHERE on macosx, and we can't use our dynamic linker mumbo
238 jumbo so easily...
239 */
240 #define my_glCallList(z)        glCallList(z)
241 #define my_glTexSubImage2D(a,b,c,d,e,f,g,h,i)   glTexSubImage2D(a,b,c,d,e,f,g,h,i)
242 #define my_glDeleteLists(a,b)   glDeleteLists(a,b)
243 #define my_glTexParameteri(a,b,c)       glTexParameteri(a,b,c)
244 #define my_glBegin(g)           glBegin(g)
245 #define my_glEnd()              glEnd()
246 #define my_glEndList()  glEndList()
247 #define my_glTexCoord2f(a,b)    glTexCoord2f(a,b)
248 #define my_glVertex2f(a,b)      glVertex2f(a,b)
249 #define my_glNewList(a,b)       glNewList(a,b)
250 #define my_glIsList(a)          glIsList(a)
251 #define my_glGenLists(a)        glGenLists(a)
252 #define my_glLoadIdentity()     glLoadIdentity()
253 #define my_glMatrixMode(a)      glMatrixMode(a)
254 #define my_glEnable(a)          glEnable(a)
255 #define my_glDisable(a)         glDisable(a)
256 #define my_glBindTexture(a,b)   glBindTexture(a,b)
257 #define my_glClear(z)           glClear(z)
258 #define my_glClearColor(a,b,c,d) glClearColor(a,b,c,d)
259 #define my_glGetString(z)       glGetString(z)
260 #define my_glTexImage2D(a,b,c,d,e,f,g,h,i)      glTexImage2D(a,b,c,d,e,f,g,h,i)
261 #define my_glGetIntegerv(a,b)   glGetIntegerv(a,b)
262 #define my_glShadeModel(a)      glShadeModel(a)
263 #define my_glGenTextures(a,b)   glGenTextures(a,b)
264 #define my_glDeleteTextures(a,b)        glDeleteTextures(a,b)
265 #define my_glViewport(a,b,c,d)  glViewport(a,b,c,d)
266 #define my_glEnableClientState(z)       glEnableClientState(z)
267 #else
268 /* again with the dynamic linker nonsense; note these are APIENTRY for compatability
269 with win32. */
270 static void (APIENTRY *my_glCallList)(GLuint);
271 static void (APIENTRY *my_glTexSubImage2D)(GLenum,GLint,GLint,GLint,
272 				GLsizei,GLsizei,GLenum,GLenum,
273 				const GLvoid *);
274 static void (APIENTRY *my_glDeleteLists)(GLuint,GLsizei);
275 static void (APIENTRY *my_glTexParameteri)(GLenum,GLenum,GLint);
276 static void (APIENTRY *my_glBegin)(GLenum);
277 static void (APIENTRY *my_glEnd)(void);
278 static void (APIENTRY *my_glEndList)(void);
279 static void (APIENTRY *my_glTexCoord2f)(GLfloat,GLfloat);
280 static void (APIENTRY *my_glVertex2f)(GLfloat,GLfloat);
281 static void (APIENTRY *my_glNewList)(GLuint, GLenum);
282 static GLboolean (APIENTRY *my_glIsList)(GLuint);
283 static GLuint (APIENTRY *my_glGenLists)(GLsizei);
284 static void (APIENTRY *my_glLoadIdentity)(void);
285 static void (APIENTRY *my_glMatrixMode)(GLenum);
286 static void (APIENTRY *my_glEnable)(GLenum);
287 static void (APIENTRY *my_glDisable)(GLenum);
288 static void (APIENTRY *my_glBindTexture)(GLenum,GLuint);
289 static void (APIENTRY *my_glClear)(GLbitfield mask);
290 static void (APIENTRY *my_glClearColor)(GLclampf,GLclampf,GLclampf,GLclampf);
291 static const GLubyte* (APIENTRY *my_glGetString)(GLenum);
292 static void (APIENTRY *my_glTexImage2D)(GLenum,GLint,GLint,GLsizei,GLsizei,GLint,
293 			GLenum,GLenum,const GLvoid *);
294 static void (APIENTRY *my_glGetIntegerv)(GLenum, GLint *);
295 static void (APIENTRY *my_glShadeModel)(GLenum);
296 static void (APIENTRY *my_glGenTextures)(GLsizei,GLuint*);
297 static void (APIENTRY *my_glDeleteTextures)(GLsizei, const GLuint *);
298 static void (APIENTRY *my_glViewport)(GLint,GLint,GLsizei,GLsizei);
299 static void (APIENTRY *my_glEnableClientState)(GLenum);
300 #endif
301 
302 static int _did_init = 0;
303 
video_driver_name(void)304 const char *video_driver_name(void)
305 {
306 	switch (video.desktop.type) {
307 	case VIDEO_SURFACE:
308 		return "sdl";
309 	case VIDEO_YUV:
310 		return "yuv";
311 	case VIDEO_GL:
312 		return "opengl";
313 	case VIDEO_DDRAW:
314 		return "directdraw";
315 	};
316 	/* err.... */
317 	return "auto";
318 }
319 
video_report(void)320 void video_report(void)
321 {
322 	char buf[256];
323 	struct {
324 		unsigned int num;
325 		const char *name, *type;
326 	} yuv_layouts[] = {
327 		{VIDEO_YUV_IYUV, "IYUV", "planar"},
328 		{VIDEO_YUV_YV12_TV, "YV12", "planar+tv"},
329 		{VIDEO_YUV_IYUV_TV, "IYUV", "planar+tv"},
330 		{VIDEO_YUV_YVYU, "YVYU", "packed"},
331 		{VIDEO_YUV_UYVY, "UYVY", "packed"},
332 		{VIDEO_YUV_YUY2, "YUY2", "packed"},
333 		{VIDEO_YUV_RGBA, "RGBA", "packed"},
334 		{VIDEO_YUV_RGBT, "RGBT", "packed"},
335 		{VIDEO_YUV_RGB565, "RGB565", "packed"},
336 		{VIDEO_YUV_RGB24, "RGB24", "packed"},
337 		{VIDEO_YUV_RGB32, "RGB32", "packed"},
338 		{0, NULL, NULL},
339 	}, *layout = yuv_layouts;
340 
341 	log_appendf(5, " Using driver '%s'", SDL_VideoDriverName(buf, 256));
342 
343 	switch (video.desktop.type) {
344 	case VIDEO_SURFACE:
345 		log_appendf(5, " %s%s video surface",
346 			(video.surface->flags & SDL_HWSURFACE) ? "Hardware" : "Software",
347 			(video.surface->flags & SDL_HWACCEL) ? " accelerated" : "");
348 		if (SDL_MUSTLOCK(video.surface))
349 			log_append(4, 0, " Must lock surface");
350 		log_appendf(5, " Display format: %d bits/pixel", video.surface->format->BitsPerPixel);
351 		break;
352 
353 	case VIDEO_YUV:
354 		/* if an overlay isn't hardware accelerated, what is it? I guess this works */
355 		log_appendf(5, " %s-accelerated video overlay",
356 			video.overlay->hw_overlay ? "Hardware" : "Non");
357 		while (video.yuvlayout != layout->num && layout->name != NULL)
358 			layout++;
359 		if (layout->name)
360 			log_appendf(5, " Display format: %s (%s)", layout->name, layout->type);
361 		else
362 			log_appendf(5, " Display format: %x", video.yuvlayout);
363 		break;
364 	case VIDEO_GL:
365 		log_appendf(5, " %s%s OpenGL interface",
366 			(video.surface->flags & SDL_HWSURFACE) ? "Hardware" : "Software",
367 			(video.surface->flags & SDL_HWACCEL) ? " accelerated" : "");
368 #if defined(NVIDIA_PixelDataRange)
369 		if (video.gl.pixel_data_range)
370 			log_append(5, 0, " NVidia pixel range extensions available");
371 #endif
372 		break;
373 	case VIDEO_DDRAW:
374 		// is this meaningful?
375 		log_appendf(5, " %s%s DirectDraw interface",
376 			(video.surface->flags & SDL_HWSURFACE) ? "Hardware" : "Software",
377 			(video.surface->flags & SDL_HWACCEL) ? " accelerated" : "");
378 		break;
379 	};
380 	log_appendf(5, " %d bits/pixel", video.surface->format->BitsPerPixel);
381 	if (video.desktop.fullscreen || video.desktop.fb_hacks) {
382 		log_appendf(5, " Display dimensions: %dx%d", video.desktop.width, video.desktop.height);
383 	}
384 }
385 
386 // check if w and h are multiples of native res (and by the same multiplier)
best_resolution(int w,int h)387 static int best_resolution(int w, int h)
388 {
389 	if ((w % NATIVE_SCREEN_WIDTH == 0)
390 	&&  (h % NATIVE_SCREEN_HEIGHT == 0)
391 	&& ((w / NATIVE_SCREEN_WIDTH) == (h / NATIVE_SCREEN_HEIGHT))) {
392 		return 1;
393 	} else {
394 		return 0;
395 	}
396 }
397 
video_is_fullscreen(void)398 int video_is_fullscreen(void)
399 {
400 	return video.desktop.fullscreen;
401 }
video_width(void)402 int video_width(void)
403 {
404 	return video.clip.w;
405 }
video_height(void)406 int video_height(void)
407 {
408 	return video.clip.h;
409 }
video_shutdown(void)410 void video_shutdown(void)
411 {
412 	if (video.desktop.fullscreen) {
413 		video.desktop.fullscreen = 0;
414 		video_resize(0,0);
415 	}
416 }
video_fullscreen(int tri)417 void video_fullscreen(int tri)
418 {
419 	if (tri == 0 || video.desktop.fb_hacks) {
420 		video.desktop.fullscreen = 0;
421 
422 	} else if (tri == 1) {
423 		video.desktop.fullscreen = 1;
424 
425 	} else if (tri < 0) {
426 		video.desktop.fullscreen = video.desktop.fullscreen ? 0 : 1;
427 	}
428 	if (_did_init) {
429 		if (video.desktop.fullscreen) {
430 			video_resize(video.desktop.width, video.desktop.height);
431 		} else {
432 			video_resize(0, 0);
433 		}
434 		/* video_report(); - this should be done in main, not here */
435 	}
436 }
437 
video_setup(const char * driver)438 void video_setup(const char *driver)
439 {
440 	char *q;
441 	/* _SOME_ drivers can be switched to, but not all of them... */
442 
443 	if (driver && strcasecmp(driver, "auto") == 0)
444 		driver = NULL;
445 
446 	video.draw.width = NATIVE_SCREEN_WIDTH;
447 	video.draw.height = NATIVE_SCREEN_HEIGHT;
448 	video.mouse.visible = MOUSE_EMULATED;
449 
450 	video.yuvlayout = VIDEO_YUV_NONE;
451 	if ((q=getenv("SCHISM_YUVLAYOUT")) || (q=getenv("YUVLAYOUT"))) {
452 		if (strcasecmp(q, "YUY2") == 0
453 		|| strcasecmp(q, "YUNV") == 0
454 		|| strcasecmp(q, "V422") == 0
455 		|| strcasecmp(q, "YUYV") == 0) {
456 			video.yuvlayout = VIDEO_YUV_YUY2;
457 		} else if (strcasecmp(q, "UYVY") == 0) {
458 			video.yuvlayout = VIDEO_YUV_UYVY;
459 		} else if (strcasecmp(q, "YVYU") == 0) {
460 			video.yuvlayout = VIDEO_YUV_YVYU;
461 		} else if (strcasecmp(q, "YV12") == 0) {
462 			video.yuvlayout = VIDEO_YUV_YV12;
463 		} else if (strcasecmp(q, "IYUV") == 0) {
464 			video.yuvlayout = VIDEO_YUV_IYUV;
465 		} else if (strcasecmp(q, "YV12/2") == 0) {
466 			video.yuvlayout = VIDEO_YUV_YV12_TV;
467 		} else if (strcasecmp(q, "IYUV/2") == 0) {
468 			video.yuvlayout = VIDEO_YUV_IYUV_TV;
469 		} else if (strcasecmp(q, "RGBA") == 0) {
470 			video.yuvlayout = VIDEO_YUV_RGBA;
471 		} else if (strcasecmp(q, "RGBT") == 0) {
472 			video.yuvlayout = VIDEO_YUV_RGBT;
473 		} else if (strcasecmp(q, "RGB565") == 0 || strcasecmp(q, "RGB2") == 0) {
474 			video.yuvlayout = VIDEO_YUV_RGB565;
475 		} else if (strcasecmp(q, "RGB24") == 0) {
476 			video.yuvlayout = VIDEO_YUV_RGB24;
477 		} else if (strcasecmp(q, "RGB32") == 0 || strcasecmp(q, "RGB") == 0) {
478 			video.yuvlayout = VIDEO_YUV_RGB32;
479 		} else if (sscanf(q, "%x", &video.yuvlayout) != 1) {
480 			video.yuvlayout = 0;
481 		}
482 	}
483 
484 	q = getenv("SCHISM_DEBUG");
485 	if (q && strstr(q,"doublebuf")) {
486 		video.desktop.doublebuf = 1;
487 	}
488 
489 	video.desktop.want_type = VIDEO_SURFACE;
490 #ifdef WIN32
491 	if (!driver) {
492 		/* alright, let's have some fun. */
493 		driver = "sdlauto"; /* err... */
494 	}
495 
496 	if (!strcasecmp(driver, "windib")) {
497 		putenv("SDL_VIDEODRIVER=windib");
498 	} else if (!strcasecmp(driver, "ddraw") || !strcasecmp(driver,"directdraw")) {
499 		putenv("SDL_VIDEODRIVER=directx");
500 		video.desktop.want_type = VIDEO_DDRAW;
501 	} else if (!strcasecmp(driver, "sdlddraw")) {
502 		putenv("SDL_VIDEODRIVER=directx");
503 	}
504 #elif defined(GEKKO)
505 	if (!driver) {
506 		driver = "yuv";
507 	}
508 #else
509 	if (!driver) {
510 		if (getenv("DISPLAY")) {
511 			driver = "x11";
512 		} else {
513 			driver = "sdlauto";
514 		}
515 	}
516 #endif
517 
518 	video.desktop.fb_hacks = 0;
519 	/* get xv info */
520 	if (video.yuvlayout == VIDEO_YUV_NONE)
521 		video.yuvlayout = os_yuvlayout();
522 	if ((video.yuvlayout != VIDEO_YUV_YV12_TV
523 	&& video.yuvlayout != VIDEO_YUV_IYUV_TV
524 	&& video.yuvlayout != VIDEO_YUV_NONE && 0) /* don't do this until we figure out how to make it better */
525 			 && !strcasecmp(driver, "x11")) {
526 		video.desktop.want_type = VIDEO_YUV;
527 		putenv((char *) "SDL_VIDEO_YUV_DIRECT=1");
528 		putenv((char *) "SDL_VIDEO_YUV_HWACCEL=1");
529 		putenv((char *) "SDL_VIDEODRIVER=x11");
530 #ifdef USE_X11
531 	} else if (!strcasecmp(driver, "dga")) {
532 		putenv((char *) "SDL_VIDEODRIVER=dga");
533 		video.desktop.want_type = VIDEO_SURFACE;
534 	} else if (!strcasecmp(driver, "directfb")) {
535 		putenv((char *) "SDL_VIDEODRIVER=directfb");
536 		video.desktop.want_type = VIDEO_SURFACE;
537 #endif
538 #if HAVE_LINUX_FB_H
539 	} else if (!strcasecmp(driver, "fbcon")
540 	|| !strcasecmp(driver, "linuxfb")
541 	|| !strcasecmp(driver, "fb")) {
542 		unset_env_var("DISPLAY");
543 		putenv((char *) "SDL_VIDEODRIVER=fbcon");
544 		video.desktop.want_type = VIDEO_SURFACE;
545 
546 	} else if (strncmp(driver, "/dev/fb", 7) == 0) {
547 		unset_env_var("DISPLAY");
548 		putenv((char *) "SDL_VIDEODRIVER=fbcon");
549 		put_env_var("SDL_FBDEV", driver);
550 		video.desktop.want_type = VIDEO_SURFACE;
551 
552 #endif
553 
554 	} else if (!strcasecmp(driver, "aalib")
555 	|| !strcasecmp(driver, "aa")) {
556 		/* SDL needs to have been built this way... */
557 		unset_env_var("DISPLAY");
558 		putenv((char *) "SDL_VIDEODRIVER=aalib");
559 		video.desktop.want_type = VIDEO_SURFACE;
560 		video.desktop.fb_hacks = 1;
561 
562 	} else if (video.yuvlayout != VIDEO_YUV_NONE && !strcasecmp(driver, "yuv")) {
563 		video.desktop.want_type = VIDEO_YUV;
564 		putenv((char *) "SDL_VIDEO_YUV_DIRECT=1");
565 		putenv((char *) "SDL_VIDEO_YUV_HWACCEL=1");
566 		/* leave everything else alone... */
567 	} else if (!strcasecmp(driver, "dummy")
568 	|| !strcasecmp(driver, "null")
569 	|| !strcasecmp(driver, "none")) {
570 
571 		unset_env_var("DISPLAY");
572 		putenv((char *) "SDL_VIDEODRIVER=dummy");
573 		video.desktop.want_type = VIDEO_SURFACE;
574 		video.desktop.fb_hacks = 1;
575 #if HAVE_SIGNAL_H
576 		signal(SIGINT, SIG_DFL);
577 #endif
578 
579 	} else if (!strcasecmp(driver, "gl") || !strcasecmp(driver, "opengl")) {
580 		video.desktop.want_type = VIDEO_GL;
581 	} else if (!strcasecmp(driver, "sdlauto")
582 	|| !strcasecmp(driver,"sdl")) {
583 		video.desktop.want_type = VIDEO_SURFACE;
584 	}
585 }
586 
video_startup(void)587 void video_startup(void)
588 {
589 	UNUSED static int did_this_2 = 0;
590 #if USE_OPENGL
591 	const char *gl_ext;
592 #endif
593 	char *q;
594 	SDL_Rect **modes;
595 	int i, j, x, y;
596 
597 	/* get monitor native res (assumed to be user's desktop res)
598 	 * first time we start video */
599 	if (display_native_x < 0 || display_native_y < 0) {
600 		const SDL_VideoInfo* info = SDL_GetVideoInfo();
601 		display_native_x = info->current_w;
602 		display_native_y = info->current_h;
603 	}
604 
605 	/* because first mode is 0 */
606 	vgamem_clear();
607 	vgamem_flip();
608 
609 	SDL_WM_SetCaption("Schism Tracker", "Schism Tracker");
610 #ifndef MACOSX
611 /* apple/macs use a bundle; this overrides their nice pretty icon */
612 #ifdef WIN32
613 /* win32 icons must be 32x32 according to SDL 1.2 doc */
614 	SDL_Surface *icon = xpmdata(_schism_icon_xpm);
615 #else
616 	SDL_Surface *icon = xpmdata(_schism_icon_xpm_hires);
617 #endif
618 	SDL_WM_SetIcon(icon, NULL);
619 	SDL_FreeSurface(icon);
620 #endif
621 
622 #ifndef MACOSX
623 	if (video.desktop.want_type == VIDEO_GL) {
624 #define Z(q) my_ ## q = SDL_GL_GetProcAddress( #q ); \
625 	if (! my_ ## q) { video.desktop.want_type = VIDEO_SURFACE; goto SKIP1; }
626 		if (did_this_2) {
627 			/* do nothing */
628 		} else if (getenv("SDL_VIDEO_GL_DRIVER")
629 		&& SDL_GL_LoadLibrary(getenv("SDL_VIDEO_GL_DRIVER")) == 0) {
630 			/* ok */
631 		} else if (SDL_GL_LoadLibrary("GL") != 0)
632 		if (SDL_GL_LoadLibrary("libGL.so") != 0)
633 		if (SDL_GL_LoadLibrary("opengl32.dll") != 0)
634 		if (SDL_GL_LoadLibrary("opengl.dll") != 0)
635 	{ /* do nothing ... because the bottom routines will fail */ }
636 		did_this_2 = 1;
637 		Z(glCallList)
638 		Z(glTexSubImage2D)
639 		Z(glDeleteLists)
640 		Z(glTexParameteri)
641 		Z(glBegin)
642 		Z(glEnd)
643 		Z(glEndList)
644 		Z(glTexCoord2f)
645 		Z(glVertex2f)
646 		Z(glNewList)
647 		Z(glIsList)
648 		Z(glGenLists)
649 		Z(glLoadIdentity)
650 		Z(glMatrixMode)
651 		Z(glEnable)
652 		Z(glDisable)
653 		Z(glBindTexture)
654 		Z(glClear)
655 		Z(glClearColor)
656 		Z(glGetString)
657 		Z(glTexImage2D)
658 		Z(glGetIntegerv)
659 		Z(glShadeModel)
660 		Z(glGenTextures)
661 		Z(glDeleteTextures)
662 		Z(glViewport)
663 		Z(glEnableClientState)
664 #undef Z
665 	}
666 SKIP1:
667 #endif
668 	if (video.desktop.want_type == VIDEO_GL) {
669 #if defined(USE_OPENGL)
670 		video.surface = SDL_SetVideoMode(640,400,0,SDL_OPENGL|SDL_RESIZABLE);
671 		if (!video.surface) {
672 			/* fallback */
673 			video.desktop.want_type = VIDEO_SURFACE;
674 		}
675 		video.gl.framebuf = NULL;
676 		video.gl.texture = 0;
677 		video.gl.displaylist = 0;
678 		my_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &video.gl.max_texsize);
679 #if defined(NVIDIA_PixelDataRange)
680 		glPixelDataRangeNV = (PFNGLPIXELDATARANGENVPROC)
681 			SDL_GL_GetProcAddress("glPixelDataRangeNV");
682 		db_glAllocateMemoryNV = (PFNWGLALLOCATEMEMORYNVPROC)
683 			SDL_GL_GetProcAddress("wglAllocateMemoryNV");
684 		db_glFreeMemoryNV = (PFNWGLFREEMEMORYNVPROC)
685 			SDL_GL_GetProcAddress("wglFreeMemoryNV");
686 #endif
687 		gl_ext = (const char *)my_glGetString(GL_EXTENSIONS);
688 		if (!gl_ext) gl_ext = (const char *)"";
689 		video.gl.packed_pixel=(strstr(gl_ext,"EXT_packed_pixels") != NULL);
690 		video.gl.paletted_texture=(strstr(gl_ext,"EXT_paletted_texture") != NULL);
691 #if defined(NVIDIA_PixelDataRange)
692 		video.gl.pixel_data_range=(strstr(gl_ext,"GL_NV_pixel_data_range") != NULL)
693 			&& glPixelDataRangeNV && db_glAllocateMemoryNV && db_glFreeMemoryNV;
694 #endif
695 #endif // USE_OPENGL
696 	}
697 
698 	x = y = -1;
699 	if ((q = getenv("SCHISM_VIDEO_RESOLUTION"))) {
700 		i = j = -1;
701 		if (sscanf(q,"%dx%d", &i,&j) == 2 && i >= 10 && j >= 10) {
702 			x = i;
703 			y = j;
704 		}
705 	}
706 #if HAVE_LINUX_FB_H
707 	if (!getenv("DISPLAY") && !video.desktop.fb_hacks) {
708 		struct fb_var_screeninfo s;
709 		int fb = -1;
710 		if (getenv("SDL_FBDEV")) {
711 			fb = open(getenv("SDL_FBDEV"), O_RDONLY);
712 		}
713 		if (fb == -1)
714 			fb = open("/dev/fb0", O_RDONLY);
715 		if (fb > -1) {
716 			if (ioctl(fb, FBIOGET_VSCREENINFO, &s) < 0) {
717 				perror("ioctl FBIOGET_VSCREENINFO");
718 			} else {
719 				if (x < 0 || y < 0) {
720 					x = s.xres;
721 					if (x < NATIVE_SCREEN_WIDTH)
722 						x = NATIVE_SCREEN_WIDTH;
723 					y = s.yres;
724 				}
725 				putenv((char *) "SDL_VIDEODRIVER=fbcon");
726 				video.desktop.bpp = s.bits_per_pixel;
727 				video.desktop.fb_hacks = 1;
728 				video.desktop.doublebuf = 1;
729 				video.desktop.fullscreen = 0;
730 				video.desktop.swsurface = 0;
731 				video.surface = SDL_SetVideoMode(x,y,
732 						video.desktop.bpp,
733 						SDL_HWSURFACE
734 						| SDL_DOUBLEBUF
735 						| SDL_ASYNCBLIT);
736 			}
737 			close(fb);
738 		}
739 	}
740 #endif
741 	if (!video.surface) {
742 		/* if we already got one... */
743 		video.surface = SDL_SetVideoMode(640,400,0,SDL_RESIZABLE);
744 		if (!video.surface) {
745 			perror("SDL_SetVideoMode");
746 			exit(255);
747 		}
748 	}
749 	video.desktop.bpp = video.surface->format->BitsPerPixel;
750 
751 	if (x < 0 || y < 0) {
752 		modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
753 		if (modes != (SDL_Rect**)0 && modes != (SDL_Rect**)-1) {
754 			for (i = 0; modes[i]; i++) {
755 				if (modes[i]->w < NATIVE_SCREEN_WIDTH) continue;
756 				if (modes[i]->h < NATIVE_SCREEN_HEIGHT)continue;
757 				if (x == -1 || y == -1 || modes[i]->w < x || modes[i]->h < y) {
758 					if (modes[i]->w != NATIVE_SCREEN_WIDTH
759 					||  modes[i]->h != NATIVE_SCREEN_HEIGHT) {
760 						if (x == NATIVE_SCREEN_WIDTH || y == NATIVE_SCREEN_HEIGHT)
761 							continue;
762 					}
763 					x = modes[i]->w;
764 					y = modes[i]->h;
765 					if (best_resolution(x,y))
766 						break;
767 				}
768 			}
769 		}
770 	}
771 	if (x < 0 || y < 0) {
772 		x = 640;
773 		y = 480;
774 	}
775 
776 	video.desktop.want_fixed = -1;
777 	q = getenv("SCHISM_VIDEO_ASPECT");
778 	if (q && (strcasecmp(q,"nofixed") == 0 || strcasecmp(q,"full")==0
779 	|| strcasecmp(q,"fit") == 0 || strcasecmp(q,"wide") == 0
780 	|| strcasecmp(q,"no-fixed") == 0))
781 		video.desktop.want_fixed = 0;
782 
783 	if ((q = getenv("SCHISM_VIDEO_DEPTH"))) {
784 		i=atoi(q);
785 		if (i == 32) video.desktop.bpp=32;
786 		else if (i == 24) video.desktop.bpp=24;
787 		else if (i == 16) video.desktop.bpp=16;
788 		else if (i == 8) video.desktop.bpp=8;
789 	}
790 
791 	/*log_appendf(2, "Ideal desktop size: %dx%d", x, y); */
792 	video.desktop.width = x;
793 	video.desktop.height = y;
794 
795 	switch (video.desktop.want_type) {
796 	case VIDEO_YUV:
797 #ifdef MACOSX
798 		video.desktop.swsurface = 1;
799 #else
800 		video.desktop.swsurface = 0;
801 #endif
802 		break;
803 
804 	case VIDEO_GL:
805 #ifdef MACOSX
806 		video.desktop.swsurface = 1;
807 #else
808 		video.desktop.swsurface = 0;
809 #endif
810 		video.gl.bilinear = cfg_video_gl_bilinear;
811 		if (video.desktop.bpp == 32 || video.desktop.bpp == 16) break;
812 		/* fall through */
813 	case VIDEO_DDRAW:
814 #ifdef WIN32
815 		if (video.desktop.bpp == 32 || video.desktop.bpp == 16) {
816 			/* good enough for here! */
817 			video.desktop.want_type = VIDEO_DDRAW;
818 			break;
819 		}
820 #endif
821 		/* fall through */
822 	case VIDEO_SURFACE:
823 		/* no scaling when using the SDL surfaces directly */
824 		video.desktop.swsurface = 1;
825 		video.desktop.want_type = VIDEO_SURFACE;
826 		break;
827 	};
828 	/* okay, i think we're ready */
829 	SDL_ShowCursor(SDL_DISABLE);
830 #if 0 /* Do we need these? Everything seems to work just fine without */
831 	SDL_EventState(SDL_VIDEORESIZE, SDL_ENABLE);
832 	SDL_EventState(SDL_VIDEOEXPOSE, SDL_ENABLE);
833 	SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
834 	SDL_EventState(SDL_USEREVENT, SDL_ENABLE);
835 	SDL_EventState(SDL_ACTIVEEVENT, SDL_ENABLE);
836 	SDL_EventState(SDL_KEYDOWN, SDL_ENABLE);
837 	SDL_EventState(SDL_KEYUP, SDL_ENABLE);
838 	SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
839 	SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_ENABLE);
840 	SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE);
841 #endif
842 
843 	_did_init = 1;
844 	video_fullscreen(video.desktop.fullscreen);
845 }
846 
_setup_surface(unsigned int w,unsigned int h,unsigned int sdlflags)847 static SDL_Surface *_setup_surface(unsigned int w, unsigned int h, unsigned int sdlflags)
848 {
849 	int want_fixed = video.desktop.want_fixed;
850 
851 	if (video.desktop.doublebuf)
852 		sdlflags |= (SDL_DOUBLEBUF|SDL_ASYNCBLIT);
853 	if (video.desktop.fullscreen) {
854 		w = video.desktop.width;
855 		h = video.desktop.height;
856 	} else {
857 		sdlflags |= SDL_RESIZABLE;
858 	}
859 
860 	if (want_fixed == -1 && best_resolution(w,h)) {
861 		want_fixed = 0;
862 	}
863 
864 	if (want_fixed) {
865 		double ratio_w = (double)w / (double)NATIVE_SCREEN_WIDTH;
866 		double ratio_h = (double)h / (double)NATIVE_SCREEN_HEIGHT;
867 		if (ratio_w < ratio_h) {
868 			video.clip.w = w;
869 			video.clip.h = (double)NATIVE_SCREEN_HEIGHT * ratio_w;
870 		} else {
871 			video.clip.h = h;
872 			video.clip.w = (double)NATIVE_SCREEN_WIDTH * ratio_h;
873 		}
874 		video.clip.x=(w-video.clip.w)/2;
875 		video.clip.y=(h-video.clip.h)/2;
876 	} else {
877 		video.clip.x = 0;
878 		video.clip.y = 0;
879 		video.clip.w = w;
880 		video.clip.h = h;
881 	}
882 
883 	if (video.desktop.fb_hacks && video.surface) {
884 		/* the original one will be _just fine_ */
885 	} else {
886 		if (video.desktop.fullscreen) {
887 			sdlflags &=~SDL_RESIZABLE;
888 			sdlflags |= SDL_FULLSCREEN;
889 		} else {
890 			sdlflags &=~SDL_FULLSCREEN;
891 			sdlflags |= SDL_RESIZABLE;
892 		}
893 		sdlflags |= (video.desktop.swsurface
894 				? SDL_SWSURFACE
895 				: SDL_HWSURFACE);
896 
897 		/* if using swsurface, get a surface the size of the whole native monitor res
898 		/* to avoid issues with weirdo display modes
899 		/* get proper aspect ratio and surface of correct size */
900 		if (video.desktop.fullscreen && video.desktop.swsurface) {
901 
902 			double ar = NATIVE_SCREEN_WIDTH / (double) NATIVE_SCREEN_HEIGHT;
903 			// ar = 4.0 / 3.0; want_fixed = 1; // uncomment for 4:3 fullscreen
904 
905 			// get maximum size that can be this AR
906 			if ((display_native_y * ar) > display_native_x) {
907 				video.clip.h = display_native_x / ar;
908 				video.clip.w = display_native_x;
909 			} else {
910 				video.clip.h = display_native_y;
911 				video.clip.w = display_native_y * ar;
912 			}
913 
914 			// clip to size (i.e. letterbox if necessary)
915 			video.clip.x = (display_native_x - video.clip.w) / 2;
916 			video.clip.y = (display_native_y - video.clip.h) / 2;
917 
918 			// get a surface the size of the whole screen @ native res
919 			w = display_native_x;
920 			h = display_native_y;
921 
922 			/* if we don't care about getting the right aspect ratio,
923 			/* sod letterboxing and just get a surface the size of the entire display */
924 			if (!want_fixed) {
925 				video.clip.w = display_native_x;
926 				video.clip.h = display_native_y;
927 				video.clip.x = 0;
928 				video.clip.y = 0;
929 			}
930 
931 		}
932 
933 		video.surface = SDL_SetVideoMode(w, h,
934 			video.desktop.bpp, sdlflags);
935 	}
936 	if (!video.surface) {
937 		perror("SDL_SetVideoMode");
938 		exit(EXIT_FAILURE);
939 	}
940 	return video.surface;
941 }
942 
943 #if USE_OPENGL
_set_gl_attributes(void)944 static void _set_gl_attributes(void)
945 {
946 	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
947 	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
948 	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32);
949 	SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, 0);
950 	SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 0);
951 	SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, 0);
952 	SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 0);
953 #if SDL_VERSION_ATLEAST(1,2,11)
954 	SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0);
955 #endif
956 }
957 #endif
958 
video_resize(unsigned int width,unsigned int height)959 void video_resize(unsigned int width, unsigned int height)
960 {
961 #if USE_OPENGL
962 	GLfloat tex_width, tex_height;
963 	int texsize;
964 #endif
965 
966 	if (!width) width = cfg_video_width;
967 	if (!height) height = cfg_video_height;
968 	video.draw.width = width;
969 	video.draw.height = height;
970 
971 	video.draw.autoscale = 1;
972 
973 	switch (video.desktop.want_type) {
974 	case VIDEO_DDRAW:
975 #ifdef WIN32
976 		if (video.ddblit.surface) {
977 			SDL_FreeSurface(video.ddblit.surface);
978 			video.ddblit.surface = 0;
979 		}
980 		memset(&video.ddblit.fx, 0, sizeof(DDBLTFX));
981 		video.ddblit.fx.dwSize = sizeof(DDBLTFX);
982 		_setup_surface(width, height, SDL_DOUBLEBUF);
983 		video.ddblit.rect.top = video.clip.y;
984 		video.ddblit.rect.left = video.clip.x;
985 		video.ddblit.rect.right = video.clip.x + video.clip.w;
986 		video.ddblit.rect.bottom = video.clip.y + video.clip.h;
987 		video.ddblit.surface = SDL_CreateRGBSurface(SDL_HWSURFACE,
988 				NATIVE_SCREEN_WIDTH, NATIVE_SCREEN_HEIGHT,
989 				video.surface->format->BitsPerPixel,
990 				video.surface->format->Rmask,
991 				video.surface->format->Gmask,
992 				video.surface->format->Bmask,0);
993 		if (video.ddblit.surface
994 		&& ((video.ddblit.surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE)) {
995 			video.desktop.type = VIDEO_DDRAW;
996 			break;
997 		}
998 		/* fall through */
999 #endif
1000 	case VIDEO_SURFACE:
1001 RETRYSURF:      /* use SDL surfaces */
1002 		video.draw.autoscale = 0;
1003 		if (video.desktop.fb_hacks
1004 		&& (video.desktop.width != NATIVE_SCREEN_WIDTH
1005 			|| video.desktop.height != NATIVE_SCREEN_HEIGHT)) {
1006 			video.draw.autoscale = 1;
1007 		}
1008 		_setup_surface(width, height, 0);
1009 		video.desktop.type = VIDEO_SURFACE;
1010 		break;
1011 
1012 	case VIDEO_YUV:
1013 		if (video.overlay) {
1014 			SDL_FreeYUVOverlay(video.overlay);
1015 			video.overlay = NULL;
1016 		}
1017 		_setup_surface(width, height, 0);
1018 		/* TODO: switch? */
1019 		switch (video.yuvlayout) {
1020 		case VIDEO_YUV_YV12_TV:
1021 			video.overlay = SDL_CreateYUVOverlay
1022 				(NATIVE_SCREEN_WIDTH, NATIVE_SCREEN_HEIGHT,
1023 				 SDL_YV12_OVERLAY, video.surface);
1024 			break;
1025 		case VIDEO_YUV_IYUV_TV:
1026 			video.overlay = SDL_CreateYUVOverlay
1027 				(NATIVE_SCREEN_WIDTH, NATIVE_SCREEN_HEIGHT,
1028 				 SDL_IYUV_OVERLAY, video.surface);
1029 			break;
1030 		case VIDEO_YUV_YV12:
1031 			video.overlay = SDL_CreateYUVOverlay
1032 				(2 * NATIVE_SCREEN_WIDTH,
1033 				 2 * NATIVE_SCREEN_HEIGHT,
1034 				 SDL_YV12_OVERLAY, video.surface);
1035 			break;
1036 		case VIDEO_YUV_IYUV:
1037 			video.overlay = SDL_CreateYUVOverlay
1038 				(2 * NATIVE_SCREEN_WIDTH,
1039 				 2 * NATIVE_SCREEN_HEIGHT,
1040 				 SDL_IYUV_OVERLAY, video.surface);
1041 			break;
1042 		case VIDEO_YUV_UYVY:
1043 			video.overlay = SDL_CreateYUVOverlay
1044 				(2 * NATIVE_SCREEN_WIDTH,
1045 				 NATIVE_SCREEN_HEIGHT,
1046 				 SDL_UYVY_OVERLAY, video.surface);
1047 			break;
1048 		case VIDEO_YUV_YVYU:
1049 			video.overlay = SDL_CreateYUVOverlay
1050 				(2 * NATIVE_SCREEN_WIDTH,
1051 				 NATIVE_SCREEN_HEIGHT,
1052 				 SDL_YVYU_OVERLAY, video.surface);
1053 			break;
1054 		case VIDEO_YUV_YUY2:
1055 			video.overlay = SDL_CreateYUVOverlay
1056 				(2 * NATIVE_SCREEN_WIDTH,
1057 				 NATIVE_SCREEN_HEIGHT,
1058 				 SDL_YUY2_OVERLAY, video.surface);
1059 			break;
1060 		case VIDEO_YUV_RGBA:
1061 		case VIDEO_YUV_RGB32:
1062 			video.overlay = SDL_CreateYUVOverlay
1063 				(4*NATIVE_SCREEN_WIDTH,
1064 				 NATIVE_SCREEN_HEIGHT,
1065 				 video.yuvlayout, video.surface);
1066 			break;
1067 		case VIDEO_YUV_RGB24:
1068 			video.overlay = SDL_CreateYUVOverlay
1069 				(3*NATIVE_SCREEN_WIDTH,
1070 				 NATIVE_SCREEN_HEIGHT,
1071 				 video.yuvlayout, video.surface);
1072 			break;
1073 		case VIDEO_YUV_RGBT:
1074 		case VIDEO_YUV_RGB565:
1075 			video.overlay = SDL_CreateYUVOverlay
1076 				(2*NATIVE_SCREEN_WIDTH,
1077 				 NATIVE_SCREEN_HEIGHT,
1078 				 video.yuvlayout, video.surface);
1079 			break;
1080 
1081 		default:
1082 			/* unknown layout */
1083 			goto RETRYSURF;
1084 		}
1085 		if (!video.overlay) {
1086 			/* can't get an overlay */
1087 			goto RETRYSURF;
1088 		}
1089 		switch (video.overlay->planes) {
1090 		case 3:
1091 		case 1:
1092 			break;
1093 		default:
1094 			/* can't get a recognized planes */
1095 			SDL_FreeYUVOverlay(video.overlay);
1096 			video.overlay = NULL;
1097 			goto RETRYSURF;
1098 		};
1099 		video.desktop.type = VIDEO_YUV;
1100 		break;
1101 #if defined(USE_OPENGL)
1102 	case VIDEO_GL:
1103 		_set_gl_attributes();
1104 		_setup_surface(width, height, SDL_OPENGL);
1105 		if (video.surface->format->BitsPerPixel < 15) {
1106 			goto RETRYSURF;
1107 		}
1108 		/* grumble... */
1109 		_set_gl_attributes();
1110 		my_glViewport(video.clip.x, video.clip.y,
1111 			video.clip.w, video.clip.h);
1112 		texsize = 2 << int_log2(NATIVE_SCREEN_WIDTH);
1113 		if (texsize > video.gl.max_texsize) {
1114 			/* can't do opengl! */
1115 			goto RETRYSURF;
1116 		}
1117 #if defined(NVIDIA_PixelDataRange)
1118 		if (video.gl.pixel_data_range) {
1119 			if (!video.gl.framebuf) {
1120 				video.gl.framebuf = db_glAllocateMemoryNV(
1121 						NATIVE_SCREEN_WIDTH*NATIVE_SCREEN_HEIGHT*4,
1122 						0.0, 1.0, 1.0);
1123 			}
1124 			glPixelDataRangeNV(GL_WRITE_PIXEL_DATA_RANGE_NV,
1125 					NATIVE_SCREEN_WIDTH*NATIVE_SCREEN_HEIGHT*4,
1126 					video.gl.framebuf);
1127 			my_glEnableClientState(GL_WRITE_PIXEL_DATA_RANGE_NV);
1128 		} else
1129 #endif
1130 		if (!video.gl.framebuf) {
1131 			video.gl.framebuf = mem_alloc(NATIVE_SCREEN_WIDTH
1132 							*NATIVE_SCREEN_HEIGHT*4);
1133 		}
1134 
1135 		video.gl.pitch = NATIVE_SCREEN_WIDTH * 4;
1136 		my_glMatrixMode(GL_PROJECTION);
1137 		my_glDeleteTextures(1, &video.gl.texture);
1138 		my_glGenTextures(1, &video.gl.texture);
1139 		my_glBindTexture(GL_TEXTURE_2D, video.gl.texture);
1140 		my_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
1141 		my_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1142 		if (video.gl.bilinear) {
1143 			my_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
1144 						GL_LINEAR);
1145 			my_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1146 						GL_LINEAR);
1147 		} else {
1148 			my_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
1149 						GL_NEAREST);
1150 			my_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1151 						GL_NEAREST);
1152 		}
1153 		my_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texsize, texsize,
1154 			0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
1155 		my_glClearColor(0.0, 0.0, 0.0, 1.0);
1156 		my_glClear(GL_COLOR_BUFFER_BIT);
1157 		SDL_GL_SwapBuffers();
1158 		my_glClear(GL_COLOR_BUFFER_BIT);
1159 		my_glShadeModel(GL_FLAT);
1160 		my_glDisable(GL_DEPTH_TEST);
1161 		my_glDisable(GL_LIGHTING);
1162 		my_glDisable(GL_CULL_FACE);
1163 		my_glEnable(GL_TEXTURE_2D);
1164 		my_glMatrixMode(GL_MODELVIEW);
1165 		my_glLoadIdentity();
1166 
1167 		tex_width = ((GLfloat)(NATIVE_SCREEN_WIDTH)/(GLfloat)texsize);
1168 		tex_height = ((GLfloat)(NATIVE_SCREEN_HEIGHT)/(GLfloat)texsize);
1169 		if (my_glIsList(video.gl.displaylist))
1170 			my_glDeleteLists(video.gl.displaylist, 1);
1171 		video.gl.displaylist = my_glGenLists(1);
1172 		my_glNewList(video.gl.displaylist, GL_COMPILE);
1173 		my_glBindTexture(GL_TEXTURE_2D, video.gl.texture);
1174 		my_glBegin(GL_QUADS);
1175 		my_glTexCoord2f(0,tex_height); my_glVertex2f(-1.0f,-1.0f);
1176 		my_glTexCoord2f(tex_width,tex_height);my_glVertex2f(1.0f,-1.0f);
1177 		my_glTexCoord2f(tex_width,0); my_glVertex2f(1.0f, 1.0f);
1178 		my_glTexCoord2f(0,0); my_glVertex2f(-1.0f, 1.0f);
1179 		my_glEnd();
1180 		my_glEndList();
1181 		video.desktop.type = VIDEO_GL;
1182 		break;
1183 #endif // USE_OPENGL
1184 	};
1185 
1186 	status.flags |= (NEED_UPDATE);
1187 }
_make_yuv(unsigned int * y,unsigned int * u,unsigned int * v,int rgb[3])1188 static void _make_yuv(unsigned int *y, unsigned int *u, unsigned int *v,
1189 						int rgb[3])
1190 {
1191 	double red, green, blue, yy, cr, cb, ry, ru, rv;
1192 	int r = rgb[0];
1193 	int g = rgb[1];
1194 	int b = rgb[2];
1195 
1196 	red = (double)r / 255.0;
1197 	green = (double)g / 255.0;
1198 	blue = (double)b / 255.0;
1199 	yy = 0.299 * red + 0.587 * green + 0.114 * blue;
1200 	cb = blue - yy;
1201 	cr = red - yy;
1202 	ry = 16.0 + 219.0 * yy;
1203 	ru = 128.0 + 126.0 * cb;
1204 	rv = 128.0 + 160.0 * cr;
1205 	*y = (uint8_t) ry;
1206 	*u = (uint8_t) ru;
1207 	*v = (uint8_t) rv;
1208 }
_yuv_pal(int i,int rgb[3])1209 static void _yuv_pal(int i, int rgb[3])
1210 {
1211 	unsigned int y,u,v;
1212 	_make_yuv(&y, &u, &v, rgb);
1213 	switch (video.yuvlayout) {
1214 	/* planar modes */
1215 	case VIDEO_YUV_YV12:
1216 	case VIDEO_YUV_IYUV:
1217 		/* this is fake; we simply record the infomration here */
1218 		video.yuv_y[i] = y|(y<<8);
1219 		video.yuv_u[i] = u;
1220 		video.yuv_v[i] = v;
1221 		break;
1222 
1223 	/* tv planar modes */
1224 	case VIDEO_YUV_YV12_TV:
1225 	case VIDEO_YUV_IYUV_TV:
1226 		/* _blitTV */
1227 		video.yuv_y[i] = y;
1228 		video.yuv_u[i] = (u >> 4) & 0xF;
1229 		video.yuv_v[i] = (v >> 4) & 0xF;
1230 		break;
1231 
1232 	/* packed modes */
1233 	case VIDEO_YUV_YVYU:
1234 		/* y0 v0 y1 u0 */
1235 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1236 		video.pal[i] = u | (y << 8) | (v << 16) | (y << 24);
1237 #else
1238 		video.pal[i] = y | (v << 8) | (y << 16) | (u << 24);
1239 #endif
1240 		break;
1241 	case VIDEO_YUV_UYVY:
1242 		/* u0 y0 v0 y1 */
1243 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1244 		video.pal[i] = y | (v << 8) | (y << 16) | (u << 24);
1245 #else
1246 		video.pal[i] = u | (y << 8) | (v << 16) | (y << 24);
1247 #endif
1248 		break;
1249 	case VIDEO_YUV_YUY2:
1250 		/* y0 u0 y1 v0 */
1251 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1252 		video.pal[i] = v | (y << 8) | (u << 16) | (y << 24);
1253 #else
1254 		video.pal[i] = y | (u << 8) | (y << 16) | (v << 24);
1255 #endif
1256 		break;
1257 	case VIDEO_YUV_RGBA:
1258 	case VIDEO_YUV_RGB32:
1259 		video.pal[i] = rgb[2] |
1260 			(rgb[1] << 8) |
1261 			(rgb[0] << 16) | (255 << 24);
1262 		break;
1263 	case VIDEO_YUV_RGB24:
1264 		video.pal[i] = rgb[2] |
1265 			(rgb[1] << 8) |
1266 			(rgb[0] << 16);
1267 		break;
1268 	case VIDEO_YUV_RGBT:
1269 		video.pal[i] =
1270 			((rgb[0] <<  8) & 0x7c00)
1271 		|       ((rgb[1] <<  3) & 0x3e0)
1272 		|       ((rgb[2] >>  2) & 0x1f);
1273 		break;
1274 	case VIDEO_YUV_RGB565:
1275 		video.pal[i] =
1276 			((rgb[0] <<  9) & 0xf800)
1277 		|       ((rgb[1] <<  4) & 0x7e0)
1278 		|       ((rgb[2] >>  2) & 0x1f);
1279 		break;
1280 	};
1281 }
_sdl_pal(int i,int rgb[3])1282 static void _sdl_pal(int i, int rgb[3])
1283 {
1284 	video.pal[i] = SDL_MapRGB(video.surface->format,
1285 			rgb[0], rgb[1], rgb[2]);
1286 }
_bgr32_pal(int i,int rgb[3])1287 static void _bgr32_pal(int i, int rgb[3])
1288 {
1289 	video.tc_bgr32[i] = rgb[2] |
1290 			(rgb[1] << 8) |
1291 			(rgb[0] << 16) | (255 << 24);
1292 }
_gl_pal(int i,int rgb[3])1293 static void _gl_pal(int i, int rgb[3])
1294 {
1295 	video.pal[i] = rgb[2] |
1296 			(rgb[1] << 8) |
1297 			(rgb[0] << 16) | (255 << 24);
1298 }
video_colors(unsigned char palette[16][3])1299 void video_colors(unsigned char palette[16][3])
1300 {
1301 	static SDL_Color imap[16];
1302 	void (*fun)(int i,int rgb[3]);
1303 	const int lastmap[] = { 0,1,2,3,5 };
1304 	int rgb[3], i, j, p;
1305 
1306 	switch (video.desktop.type) {
1307 	case VIDEO_SURFACE:
1308 		if (video.surface->format->BytesPerPixel == 1) {
1309 			const int depthmap[] = { 0, 15,14,7,
1310 						8, 8, 9, 12,
1311 						6, 1, 2, 2,
1312 						10, 3, 11, 11 };
1313 			/* okay, indexed color */
1314 			for (i = 0; i < 16; i++) {
1315 				video.pal[i] = i;
1316 				imap[i].r = palette[i][0];
1317 				imap[i].g = palette[i][1];
1318 				imap[i].b = palette[i][2];
1319 
1320 				rgb[0]=palette[i][0];
1321 				rgb[1]=palette[i][1];
1322 				rgb[2]=palette[i][2];
1323 				_bgr32_pal(i, rgb);
1324 
1325 			}
1326 			for (i = 128; i < 256; i++) {
1327 				video.pal[i] = depthmap[(i>>4)];
1328 			}
1329 			for (i = 128; i < 256; i++) {
1330 				j = i - 128;
1331 				p = lastmap[(j>>5)];
1332 				rgb[0] = (int)palette[p][0] +
1333 					(((int)(palette[p+1][0]
1334 					- palette[p][0]) * (j&31)) /32);
1335 				rgb[1] = (int)palette[p][1] +
1336 					(((int)(palette[p+1][1]
1337 					- palette[p][1]) * (j&31)) /32);
1338 				rgb[2] = (int)palette[p][2] +
1339 					(((int)(palette[p+1][2]
1340 					- palette[p][2]) * (j&31)) /32);
1341 				_bgr32_pal(i, rgb);
1342 			}
1343 			SDL_SetColors(video.surface, imap, 0, 16);
1344 			return;
1345 		}
1346 		/* fall through */
1347 	case VIDEO_DDRAW:
1348 		fun = _sdl_pal;
1349 		break;
1350 	case VIDEO_YUV:
1351 		fun = _yuv_pal;
1352 		break;
1353 	case VIDEO_GL:
1354 		fun = _gl_pal;
1355 		break;
1356 	default:
1357 		/* eh? */
1358 		return;
1359 	};
1360 	/* make our "base" space */
1361 	for (i = 0; i < 16; i++) {
1362 		rgb[0]=palette[i][0];
1363 		rgb[1]=palette[i][1];
1364 		rgb[2]=palette[i][2];
1365 		fun(i, rgb);
1366 		_bgr32_pal(i, rgb);
1367 	}
1368 	/* make our "gradient" space */
1369 	for (i = 128; i < 256; i++) {
1370 		j = i - 128;
1371 		p = lastmap[(j>>5)];
1372 		rgb[0] = (int)palette[p][0] +
1373 			(((int)(palette[p+1][0] - palette[p][0]) * (j&31)) /32);
1374 		rgb[1] = (int)palette[p][1] +
1375 			(((int)(palette[p+1][1] - palette[p][1]) * (j&31)) /32);
1376 		rgb[2] = (int)palette[p][2] +
1377 			(((int)(palette[p+1][2] - palette[p][2]) * (j&31)) /32);
1378 		fun(i, rgb);
1379 		_bgr32_pal(i, rgb);
1380 	}
1381 }
1382 
video_refresh(void)1383 void video_refresh(void)
1384 {
1385 	vgamem_flip();
1386 	vgamem_clear();
1387 }
1388 
make_mouseline(unsigned int x,unsigned int v,unsigned int y,unsigned int mouseline[80])1389 static inline void make_mouseline(unsigned int x, unsigned int v, unsigned int y, unsigned int mouseline[80])
1390 {
1391 	unsigned int z;
1392 
1393 	memset(mouseline, 0, 80*sizeof(unsigned int));
1394 	if (video.mouse.visible != MOUSE_EMULATED
1395 	    || !(status.flags & IS_FOCUSED)
1396 	    || y < video.mouse.y
1397 	    || y >= video.mouse.y+MOUSE_HEIGHT) {
1398 		return;
1399 	}
1400 
1401 	z = _mouse_pointer[ y - video.mouse.y ];
1402 	mouseline[x] = z >> v;
1403 	if (x < 79) mouseline[x+1] = (z << (8-v)) & 0xff;
1404 }
1405 
1406 
1407 #define FIXED_BITS 8
1408 #define FIXED_MASK ((1 << FIXED_BITS) - 1)
1409 #define ONE_HALF_FIXED (1 << (FIXED_BITS - 1))
1410 #define INT2FIXED(x) ((x) << FIXED_BITS)
1411 #define FIXED2INT(x) ((x) >> FIXED_BITS)
1412 #define FRAC(x) ((x) & FIXED_MASK)
1413 
_blit1n(int bpp,unsigned char * pixels,unsigned int pitch)1414 static void _blit1n(int bpp, unsigned char *pixels, unsigned int pitch)
1415 {
1416 	unsigned int *csp, *esp, *dp;
1417 	unsigned int c00, c01, c10, c11;
1418 	unsigned int outr, outg, outb;
1419 	unsigned int pad;
1420 	int fixedx, fixedy, scalex, scaley;
1421 	unsigned int y, x,ey,ex,t1,t2;
1422 	unsigned int mouseline[80];
1423 	unsigned int mouseline_x, mouseline_v;
1424 	int iny, lasty;
1425 
1426 	mouseline_x = (video.mouse.x / 8);
1427 	mouseline_v = (video.mouse.x % 8);
1428 
1429 	csp = (unsigned int *)video.cv32backing;
1430 	esp = csp + NATIVE_SCREEN_WIDTH;
1431 	lasty = -2;
1432 	iny = 0;
1433 	pad = pitch - (video.clip.w * bpp);
1434 	scalex = INT2FIXED(NATIVE_SCREEN_WIDTH-1) / video.clip.w;
1435 	scaley = INT2FIXED(NATIVE_SCREEN_HEIGHT-1) / video.clip.h;
1436 	for (y = 0, fixedy = 0; (y < video.clip.h); y++, fixedy += scaley) {
1437 		iny = FIXED2INT(fixedy);
1438 		if (iny != lasty) {
1439 			make_mouseline(mouseline_x, mouseline_v, iny, mouseline);
1440 
1441 			/* we'll downblit the colors later */
1442 			if (iny == lasty + 1) {
1443 				/* move up one line */
1444 				vgamem_scan32(iny+1, csp, video.tc_bgr32, mouseline);
1445 				dp = esp; esp = csp; csp=dp;
1446 			} else {
1447 				vgamem_scan32(iny, (csp = (unsigned int *)video.cv32backing),
1448 					video.tc_bgr32, mouseline);
1449 				vgamem_scan32(iny+1, (esp = (csp + NATIVE_SCREEN_WIDTH)),
1450 					video.tc_bgr32, mouseline);
1451 			}
1452 			lasty = iny;
1453 		}
1454 		for (x = 0, fixedx = 0; x < video.clip.w; x++, fixedx += scalex) {
1455 			ex = FRAC(fixedx);
1456 			ey = FRAC(fixedy);
1457 
1458 			c00 = csp[FIXED2INT(fixedx)];
1459 			c01 = csp[FIXED2INT(fixedx) + 1];
1460 			c10 = esp[FIXED2INT(fixedx)];
1461 			c11 = esp[FIXED2INT(fixedx) + 1];
1462 
1463 #if FIXED_BITS <= 8
1464 			/* When there are enough bits between blue and
1465 			 * red, do the RB channels together
1466 			 * See http://www.virtualdub.org/blog/pivot/entry.php?id=117
1467 			 * for a quick explanation */
1468 #define REDBLUE(Q) ((Q) & 0x00FF00FF)
1469 #define GREEN(Q) ((Q) & 0x0000FF00)
1470 			t1 = REDBLUE((((REDBLUE(c01)-REDBLUE(c00))*ex) >> FIXED_BITS)+REDBLUE(c00));
1471 			t2 = REDBLUE((((REDBLUE(c11)-REDBLUE(c10))*ex) >> FIXED_BITS)+REDBLUE(c10));
1472 			outb = ((((t2-t1)*ey) >> FIXED_BITS) + t1);
1473 
1474 			t1 = GREEN((((GREEN(c01)-GREEN(c00))*ex) >> FIXED_BITS)+GREEN(c00));
1475 			t2 = GREEN((((GREEN(c11)-GREEN(c10))*ex) >> FIXED_BITS)+GREEN(c10));
1476 			outg = (((((t2-t1)*ey) >> FIXED_BITS) + t1) >> 8) & 0xFF;
1477 
1478 			outr = (outb >> 16) & 0xFF;
1479 			outb &= 0xFF;
1480 #undef REDBLUE
1481 #undef GREEN
1482 #else
1483 #define BLUE(Q) (Q & 255)
1484 #define GREEN(Q) ((Q >> 8) & 255)
1485 #define RED(Q) ((Q >> 16) & 255)
1486 			t1 = ((((BLUE(c01)-BLUE(c00))*ex) >> FIXED_BITS)+BLUE(c00)) & 0xFF;
1487 			t2 = ((((BLUE(c11)-BLUE(c10))*ex) >> FIXED_BITS)+BLUE(c10)) & 0xFF;
1488 			outb = ((((t2-t1)*ey) >> FIXED_BITS) + t1);
1489 
1490 			t1 = ((((GREEN(c01)-GREEN(c00))*ex) >> FIXED_BITS)+GREEN(c00)) & 0xFF;
1491 			t2 = ((((GREEN(c11)-GREEN(c10))*ex) >> FIXED_BITS)+GREEN(c10)) & 0xFF;
1492 			outg = ((((t2-t1)*ey) >> FIXED_BITS) + t1);
1493 
1494 			t1 = ((((RED(c01)-RED(c00))*ex) >> FIXED_BITS)+RED(c00)) & 0xFF;
1495 			t2 = ((((RED(c11)-RED(c10))*ex) >> FIXED_BITS)+RED(c10)) & 0xFF;
1496 			outr = ((((t2-t1)*ey) >> FIXED_BITS) + t1);
1497 #undef RED
1498 #undef GREEN
1499 #undef BLUE
1500 #endif
1501 			/* write output "pixel" */
1502 			switch (bpp) {
1503 			case 4:
1504 				/* inline MapRGB */
1505 				(*(unsigned int *)pixels) = 0xFF000000 | (outr << 16) | (outg << 8) | outb;
1506 				break;
1507 			case 3:
1508 				/* inline MapRGB */
1509 				(*(unsigned int *)pixels) = (outr << 16) | (outg << 8) | outb;
1510 				break;
1511 			case 2:
1512 				/* inline MapRGB if possible */
1513 				if (video.surface->format->palette) {
1514 					/* err... */
1515 					(*(unsigned short *)pixels) = SDL_MapRGB(
1516 						video.surface->format, outr, outg, outb);
1517 				} else if (video.surface->format->Gloss == 2) {
1518 					/* RGB565 */
1519 					(*(unsigned short *)pixels) = ((outr << 8) & 0xF800) |
1520 						((outg << 3) & 0x07E0) |
1521 						(outb >> 3);
1522 				} else {
1523 					/* RGB555 */
1524 					(*(unsigned short *)pixels) = 0x8000 |
1525 						((outr << 7) & 0x7C00) |
1526 						((outg << 2) & 0x03E0) |
1527 						(outb >> 3);
1528 				}
1529 				break;
1530 			case 1:
1531 				/* er... */
1532 				(*pixels) = SDL_MapRGB(
1533 					video.surface->format, outr, outg, outb);
1534 				break;
1535 			};
1536 			pixels += bpp;
1537 		}
1538 		pixels += pad;
1539 	}
1540 }
_blitYY(unsigned char * pixels,unsigned int pitch,unsigned int * tpal)1541 static void _blitYY(unsigned char *pixels, unsigned int pitch, unsigned int *tpal)
1542 {
1543 	unsigned int mouseline_x = (video.mouse.x / 8);
1544 	unsigned int mouseline_v = (video.mouse.x % 8);
1545 	unsigned int mouseline[80];
1546 	int y;
1547 
1548 	for (y = 0; y < NATIVE_SCREEN_HEIGHT; y++) {
1549 		make_mouseline(mouseline_x, mouseline_v, y, mouseline);
1550 
1551 		vgamem_scan16(y, (unsigned short *)pixels, tpal, mouseline);
1552 		memcpy(pixels+pitch,pixels,pitch);
1553 		pixels += pitch;
1554 		pixels += pitch;
1555 	}
1556 }
_blitUV(unsigned char * pixels,unsigned int pitch,unsigned int * tpal)1557 static void _blitUV(unsigned char *pixels, unsigned int pitch, unsigned int *tpal)
1558 {
1559 	unsigned int mouseline_x = (video.mouse.x / 8);
1560 	unsigned int mouseline_v = (video.mouse.x % 8);
1561 	unsigned int mouseline[80];
1562 	int y;
1563 	for (y = 0; y < NATIVE_SCREEN_HEIGHT; y++) {
1564 		make_mouseline(mouseline_x, mouseline_v, y, mouseline);
1565 		vgamem_scan8(y, (unsigned char *)pixels, tpal, mouseline);
1566 		pixels += pitch;
1567 	}
1568 }
_blitTV(unsigned char * pixels,UNUSED unsigned int pitch,unsigned int * tpal)1569 static void _blitTV(unsigned char *pixels, UNUSED unsigned int pitch, unsigned int *tpal)
1570 {
1571 	unsigned int mouseline_x = (video.mouse.x / 8);
1572 	unsigned int mouseline_v = (video.mouse.x % 8);
1573 	unsigned int mouseline[80];
1574 	int y, x;
1575 	for (y = 0; y < NATIVE_SCREEN_HEIGHT; y += 2) {
1576 		make_mouseline(mouseline_x, mouseline_v, y, mouseline);
1577 		vgamem_scan8(y, (unsigned char *)video.cv8backing, tpal, mouseline);
1578 		for (x = 0; x < NATIVE_SCREEN_WIDTH; x += 2) {
1579 			*pixels++ = video.cv8backing[x+1]
1580 				| (video.cv8backing[x] << 4);
1581 		}
1582 	}
1583 }
1584 
_blit11(int bpp,unsigned char * pixels,unsigned int pitch,unsigned int * tpal)1585 static void _blit11(int bpp, unsigned char *pixels, unsigned int pitch,
1586 			unsigned int *tpal)
1587 {
1588 	unsigned int mouseline_x = (video.mouse.x / 8);
1589 	unsigned int mouseline_v = (video.mouse.x % 8);
1590 	unsigned int mouseline[80];
1591 	unsigned char *pdata;
1592 	unsigned int x, y;
1593 	int pitch24;
1594 
1595 	switch (bpp) {
1596 	case 4:
1597 		for (y = 0; y < NATIVE_SCREEN_HEIGHT; y++) {
1598 			make_mouseline(mouseline_x, mouseline_v, y, mouseline);
1599 			vgamem_scan32(y, (unsigned int *)pixels, tpal, mouseline);
1600 			pixels += pitch;
1601 		}
1602 		break;
1603 	case 3:
1604 		/* ... */
1605 		pitch24 = pitch - (NATIVE_SCREEN_WIDTH * 3);
1606 		if (pitch24 < 0) {
1607 			return; /* eh? */
1608 		}
1609 		for (y = 0; y < NATIVE_SCREEN_HEIGHT; y++) {
1610 			make_mouseline(mouseline_x, mouseline_v, y, mouseline);
1611 			vgamem_scan32(y,(unsigned int*)video.cv32backing,tpal, mouseline);
1612 			/* okay... */
1613 			pdata = video.cv32backing;
1614 			for (x = 0; x < NATIVE_SCREEN_WIDTH; x++) {
1615 #if WORDS_BIGENDIAN
1616 				memcpy(pixels, pdata+1, 3);
1617 #else
1618 				memcpy(pixels, pdata, 3);
1619 #endif
1620 				pdata += 4;
1621 				pixels += 3;
1622 			}
1623 			pixels += pitch24;
1624 		}
1625 		break;
1626 	case 2:
1627 		for (y = 0; y < NATIVE_SCREEN_HEIGHT; y++) {
1628 			make_mouseline(mouseline_x, mouseline_v, y, mouseline);
1629 			vgamem_scan16(y, (unsigned short *)pixels, tpal, mouseline);
1630 			pixels += pitch;
1631 		}
1632 		break;
1633 	case 1:
1634 		for (y = 0; y < NATIVE_SCREEN_HEIGHT; y++) {
1635 			make_mouseline(mouseline_x, mouseline_v, y, mouseline);
1636 			vgamem_scan8(y, (unsigned char *)pixels, tpal, mouseline);
1637 			pixels += pitch;
1638 		}
1639 		break;
1640 	};
1641 }
1642 
_video_blit_planar(void)1643 static void _video_blit_planar(void) {
1644 	SDL_LockYUVOverlay(video.overlay);
1645 	vgamem_lock();
1646 
1647 	switch (video.yuvlayout) {
1648 	case VIDEO_YUV_YV12_TV:
1649 		/* halfwidth Y+V+U */
1650 		_blitUV(video.overlay->pixels[0], video.overlay->pitches[0], video.yuv_y);
1651 		_blitTV(video.overlay->pixels[1], video.overlay->pitches[1], video.yuv_v);
1652 		_blitTV(video.overlay->pixels[2], video.overlay->pitches[2], video.yuv_u);
1653 		break;
1654 	case VIDEO_YUV_IYUV_TV:
1655 		/* halfwidth Y+U+V */
1656 		_blitUV(video.overlay->pixels[0], video.overlay->pitches[0], video.yuv_y);
1657 		_blitTV(video.overlay->pixels[1], video.overlay->pitches[1], video.yuv_u);
1658 		_blitTV(video.overlay->pixels[2], video.overlay->pitches[2], video.yuv_v);
1659 		break;
1660 
1661 	case VIDEO_YUV_YV12:
1662 		/* Y+V+U */
1663 		_blitYY(video.overlay->pixels[0], video.overlay->pitches[0], video.yuv_y);
1664 		_blitUV(video.overlay->pixels[1], video.overlay->pitches[1], video.yuv_v);
1665 		_blitUV(video.overlay->pixels[2], video.overlay->pitches[2], video.yuv_u);
1666 		break;
1667 	case VIDEO_YUV_IYUV:
1668 		/* Y+U+V */
1669 		_blitYY(video.overlay->pixels[0], video.overlay->pitches[0], video.yuv_y);
1670 		_blitUV(video.overlay->pixels[1], video.overlay->pitches[1], video.yuv_u);
1671 		_blitUV(video.overlay->pixels[2], video.overlay->pitches[2], video.yuv_v);
1672 		break;
1673 	};
1674 
1675 	vgamem_unlock();
1676 
1677 	SDL_UnlockYUVOverlay(video.overlay);
1678 	SDL_DisplayYUVOverlay(video.overlay, &video.clip);
1679 }
1680 
video_blit(void)1681 void video_blit(void)
1682 {
1683 	unsigned char *pixels = NULL;
1684 	unsigned int bpp = 0;
1685 	unsigned int pitch = 0;
1686 
1687 	switch (video.desktop.type) {
1688 	case VIDEO_SURFACE:
1689 		if (SDL_MUSTLOCK(video.surface)) {
1690 			while (SDL_LockSurface(video.surface) == -1) {
1691 				SDL_Delay(10);
1692 			}
1693 		}
1694 		bpp = video.surface->format->BytesPerPixel;
1695 		pixels = (unsigned char *)video.surface->pixels;
1696 		pixels += video.clip.y * video.surface->pitch;
1697 		pixels += video.clip.x * bpp;
1698 		pitch = video.surface->pitch;
1699 		break;
1700 	case VIDEO_YUV:
1701 		if (video.overlay->planes == 3) {
1702 			_video_blit_planar();
1703 			return;
1704 		}
1705 
1706 		SDL_LockYUVOverlay(video.overlay);
1707 		pixels = (unsigned char *)*(video.overlay->pixels);
1708 		pitch = *(video.overlay->pitches);
1709 		switch (video.yuvlayout) {
1710 		case VIDEO_YUV_RGBT:   bpp = 2; break;
1711 		case VIDEO_YUV_RGB565: bpp = 2; break;
1712 		case VIDEO_YUV_RGB24:  bpp = 3; break;
1713 		default:
1714 			bpp = 4;
1715 		};
1716 		break;
1717 	case VIDEO_GL:
1718 		pixels = (unsigned char *)video.gl.framebuf;
1719 		pitch = video.gl.pitch;
1720 		bpp = 4;
1721 		break;
1722 	case VIDEO_DDRAW:
1723 #ifdef WIN32
1724 		if (SDL_MUSTLOCK(video.ddblit.surface)) {
1725 			while (SDL_LockSurface(video.ddblit.surface) == -1) {
1726 				SDL_Delay(10);
1727 			}
1728 		}
1729 		pixels = (unsigned char *)video.ddblit.surface->pixels;
1730 		pitch = video.ddblit.surface->pitch;
1731 		bpp = video.surface->format->BytesPerPixel;
1732 		break;
1733 #else
1734 		return; /* eh? */
1735 #endif
1736 	};
1737 
1738 	vgamem_lock();
1739 	if (video.draw.autoscale
1740 	    || (video.clip.w == NATIVE_SCREEN_WIDTH && video.clip.h == NATIVE_SCREEN_HEIGHT)) {
1741 		/* scaling is provided by the hardware, or isn't necessary */
1742 		_blit11(bpp, pixels, pitch, video.pal);
1743 	} else {
1744 		_blit1n(bpp, pixels, pitch);
1745 	}
1746 	vgamem_unlock();
1747 
1748 	switch (video.desktop.type) {
1749 	case VIDEO_SURFACE:
1750 		if (SDL_MUSTLOCK(video.surface)) {
1751 			SDL_UnlockSurface(video.surface);
1752 		}
1753 		SDL_Flip(video.surface);
1754 		break;
1755 #ifdef WIN32
1756 	case VIDEO_DDRAW:
1757 		if (SDL_MUSTLOCK(video.ddblit.surface)) {
1758 			SDL_UnlockSurface(video.ddblit.surface);
1759 		}
1760 		switch (IDirectDrawSurface3_Blt(
1761 				video.surface->hwdata->dd_writebuf,
1762 				&video.ddblit.rect,
1763 				video.ddblit.surface->hwdata->dd_surface,0,
1764 				DDBLT_WAIT, NULL)) {
1765 		case DD_OK:
1766 			break;
1767 		case DDERR_SURFACELOST:
1768 			IDirectDrawSurface3_Restore(video.ddblit.surface->hwdata->dd_surface);
1769 			IDirectDrawSurface3_Restore(video.surface->hwdata->dd_surface);
1770 			break;
1771 		default:
1772 			break;
1773 		};
1774 		SDL_Flip(video.surface);
1775 		break;
1776 #endif
1777 	case VIDEO_YUV:
1778 		SDL_UnlockYUVOverlay(video.overlay);
1779 		SDL_DisplayYUVOverlay(video.overlay, &video.clip);
1780 		break;
1781 #if defined(USE_OPENGL)
1782 	case VIDEO_GL:
1783 		my_glBindTexture(GL_TEXTURE_2D, video.gl.texture);
1784 		my_glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
1785 			NATIVE_SCREEN_WIDTH, NATIVE_SCREEN_HEIGHT,
1786 			GL_BGRA_EXT,
1787 			GL_UNSIGNED_INT_8_8_8_8_REV,
1788 			video.gl.framebuf);
1789 		my_glCallList(video.gl.displaylist);
1790 		SDL_GL_SwapBuffers();
1791 		break;
1792 #endif
1793 	};
1794 }
1795 
video_mousecursor_visible(void)1796 int video_mousecursor_visible(void)
1797 {
1798 	return video.mouse.visible;
1799 }
1800 
video_mousecursor(int vis)1801 void video_mousecursor(int vis)
1802 {
1803 	const char *state[] = {
1804 		"Mouse disabled",
1805 		"Software mouse cursor enabled",
1806 		"Hardware mouse cursor enabled",
1807 	};
1808 
1809 	if (status.flags & NO_MOUSE) {
1810 		// disable it no matter what
1811 		video.mouse.visible = MOUSE_DISABLED;
1812 		//SDL_ShowCursor(0);
1813 		return;
1814 	}
1815 
1816 	switch (vis) {
1817 	case MOUSE_CYCLE_STATE:
1818 		vis = (video.mouse.visible + 1) % MOUSE_CYCLE_STATE;
1819 		/* fall through */
1820 	case MOUSE_DISABLED:
1821 	case MOUSE_SYSTEM:
1822 	case MOUSE_EMULATED:
1823 		video.mouse.visible = vis;
1824 		status_text_flash("%s", state[video.mouse.visible]);
1825 	case MOUSE_RESET_STATE:
1826 		break;
1827 	default:
1828 		video.mouse.visible = MOUSE_EMULATED;
1829 	}
1830 
1831 	SDL_ShowCursor(video.mouse.visible == MOUSE_SYSTEM);
1832 
1833 	// Totally turn off mouse event sending when the mouse is disabled
1834 	int evstate = video.mouse.visible == MOUSE_DISABLED ? SDL_DISABLE : SDL_ENABLE;
1835 	if (evstate != SDL_EventState(SDL_MOUSEMOTION, SDL_QUERY)) {
1836 		SDL_EventState(SDL_MOUSEMOTION, evstate);
1837 		SDL_EventState(SDL_MOUSEBUTTONDOWN, evstate);
1838 		SDL_EventState(SDL_MOUSEBUTTONUP, evstate);
1839 	}
1840 }
1841 
video_gl_bilinear(void)1842 int video_gl_bilinear(void)
1843 {
1844 	return video.gl.bilinear;
1845 }
1846 
video_translate(unsigned int vx,unsigned int vy,unsigned int * x,unsigned int * y)1847 void video_translate(unsigned int vx, unsigned int vy,
1848 		unsigned int *x, unsigned int *y)
1849 {
1850 	if ((signed) vx < video.clip.x) vx = video.clip.x;
1851 	vx -= video.clip.x;
1852 
1853 	if ((signed) vy < video.clip.y) vy = video.clip.y;
1854 	vy -= video.clip.y;
1855 
1856 	if ((signed) vx > video.clip.w) vx = video.clip.w;
1857 	if ((signed) vy > video.clip.h) vy = video.clip.h;
1858 
1859 	vx *= NATIVE_SCREEN_WIDTH;
1860 	vy *= NATIVE_SCREEN_HEIGHT;
1861 	vx /= (video.draw.width - (video.draw.width - video.clip.w));
1862 	vy /= (video.draw.height - (video.draw.height - video.clip.h));
1863 
1864 	if (video.mouse.visible && (video.mouse.x != vx || video.mouse.y != vy)) {
1865 		status.flags |= SOFTWARE_MOUSE_MOVED;
1866 	}
1867 	video.mouse.x = vx;
1868 	video.mouse.y = vy;
1869 	if (x) *x = vx;
1870 	if (y) *y = vy;
1871 }
1872 
1873