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