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