diff -purN gnuboy-1.0.3/Makefile.in gnuboy-1.0.3-nk/Makefile.in --- gnuboy-1.0.3/Makefile.in Tue Jul 3 12:31:18 2001 +++ gnuboy-1.0.3-nk/Makefile.in Thu Oct 28 00:43:49 2004 @@ -29,6 +29,8 @@ SVGA_LIBS = -L/usr/local/lib -lvga SDL_OBJS = sys/sdl/sdl.o sys/sdl/keymap.o SDL_LIBS = @SDL_LIBS@ SDL_CFLAGS = @SDL_CFLAGS@ +GL_CFLAGS = @GL_CFLAGS@ +GL_LIBS = @GL_LIBS@ X11_OBJS = sys/x11/xlib.o sys/x11/keymap.o @JOY@ @SOUND@ X11_LIBS = @XLIBS@ -lX11 -lXext @@ -44,10 +46,10 @@ sgnuboy: $(OBJS) $(SYS_OBJS) $(SVGA_OBJS $(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(SVGA_OBJS) -o $@ $(SVGA_LIBS) sdlgnuboy: $(OBJS) $(SYS_OBJS) $(SDL_OBJS) - $(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(SDL_OBJS) -o $@ $(SDL_LIBS) + $(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(SDL_OBJS) -o $@ $(SDL_LIBS) $(GL_LIBS) sys/sdl/sdl.o: sys/sdl/sdl.c - $(MYCC) $(SDL_CFLAGS) -c $< -o $@ + $(MYCC) $(SDL_CFLAGS) $(GL_CFLAGS) -c $< -o $@ sys/sdl/keymap.o: sys/sdl/keymap.c $(MYCC) $(SDL_CFLAGS) -c $< -o $@ diff -purN gnuboy-1.0.3/configure.in gnuboy-1.0.3-nk/configure.in --- gnuboy-1.0.3/configure.in Sun Sep 23 21:09:31 2001 +++ gnuboy-1.0.3-nk/configure.in Thu Oct 28 16:41:12 2004 @@ -128,6 +128,7 @@ AC_ARG_ENABLE(profile, [ --enable-prof AC_ARG_ENABLE(arch, [ --enable-arch compile for specific host cpu architecture], [], [enable_arch=yes]) AC_ARG_ENABLE(optimize, [ --enable-optimize=LEVEL select optimization level (full,low,none)], [], [enable_optimize=yes]) AC_ARG_ENABLE(asm, [ --enable-asm use hand-optimized asm cores], [], [enable_asm=yes]) +AC_ARG_ENABLE(opengl, [ --enable-opengl use OpenGL for scaling], [], [enable_opengl=yes]) if test "$enable_warnings" = yes ; then @@ -238,6 +239,20 @@ AC_MSG_RESULT(no optimized asm core avai esac fi +if test "$enable_opengl" != "no" ; then +AC_CHECK_LIB(GL, glTexImage2D, [ +AC_CHECK_HEADERS(GL/gl.h, ,[ +AC_MSG_WARN(OpenGL found but headers are missing!!) +enable_opengl=no +])], [enable_opengl=no]) +fi + + +if test "$enable_opengl" != "no" ; then +GL_CFLAGS="-DUSE_OGL" +GL_LIBS="-lGL" +AC_MSG_RESULT(using OpenGL) +fi AC_SUBST(SYS_DEFS) AC_SUBST(ENDIAN) @@ -245,6 +260,8 @@ AC_SUBST(SOUND) AC_SUBST(JOY) AC_SUBST(ASM) AC_SUBST(ASM_OBJS) +AC_SUBST(GL_CFLAGS) +AC_SUBST(GL_LIBS) AC_SUBST(FB_OBJS) AC_SUBST(SDL_CFLAGS) AC_SUBST(SDL_LIBS) diff -purN gnuboy-1.0.3/sys/sdl/sdl.c gnuboy-1.0.3-nk/sys/sdl/sdl.c --- gnuboy-1.0.3/sys/sdl/sdl.c Mon Sep 17 12:40:14 2001 +++ gnuboy-1.0.3-nk/sys/sdl/sdl.c Thu Oct 28 18:51:43 2004 @@ -5,6 +5,7 @@ * (C) 2001 Damian Gryski * Joystick code contributed by David Lau * Sound code added by Laguna + * OpenGL, multiple YUV modes, and resizing added by Nicholas Kain * * Licensed under the GPLv2, or later. */ @@ -13,17 +14,22 @@ #include #include - +#ifdef USE_OGL +#include +#endif #include "fb.h" #include "input.h" #include "rc.h" + struct fb fb; static int use_yuv = -1; static int fullscreen = 1; static int use_altenter = 1; +static int resizable = 1; +static int keepaspect = 1; static int use_joy = 1, sdl_joy_num; static SDL_Joystick * sdl_joy = NULL; static const int joy_commit_range = 3276; @@ -33,6 +39,16 @@ static SDL_Surface *screen; static SDL_Overlay *overlay; static SDL_Rect overlay_rect; +#ifdef USE_OGL +static int use_ogl = -1; +static int use_bilinear = 0; +static int ogl = 0; +static GLuint ogl_texture; +static GLuint ogl_list; +static byte *ogl_framebuf = 0; +static int ogl_pitch; +#endif + static int vmode[3] = { 0, 0, 16 }; rcvar_t vid_exports[] = @@ -41,6 +57,12 @@ rcvar_t vid_exports[] = RCV_BOOL("yuv", &use_yuv), RCV_BOOL("fullscreen", &fullscreen), RCV_BOOL("altenter", &use_altenter), + RCV_BOOL("resize", &resizable), + RCV_BOOL("keepaspect", &keepaspect), +#ifdef USE_OGL + RCV_BOOL("opengl", &use_ogl), + RCV_BOOL("bilinear", &use_bilinear), +#endif RCV_END }; @@ -50,6 +72,24 @@ rcvar_t joy_exports[] = RCV_END }; +static const int valid_overlay[] = +{ + SDL_UYVY_OVERLAY, + SDL_YUY2_OVERLAY, + SDL_YVYU_OVERLAY, + 0 +}; + +static const int valid_bpp[] = +{ + 32, + 24, + 16, + 15, + 8, + 0 +}; + /* keymap - mappings of the form { scancode, localcode } - from sdl/keymap.c */ extern int keymap[][2]; @@ -101,27 +141,226 @@ static void joy_init() SDL_JoystickEventState(SDL_ENABLE); } -static void overlay_init() +static void sdl_setmode(int flags) +{ + int i; + + flags |= SDL_HWSURFACE; + + if (fullscreen) + flags |= SDL_FULLSCREEN; + + if (!resizable) + flags &= ~SDL_RESIZABLE; + + if (SDL_Init(SDL_INIT_VIDEO)) + die("SDL: Couldn't initialize SDL: %s\n", SDL_GetError()); + + for (i=0; valid_bpp[i]; ++i) + if (SDL_VideoModeOK(vmode[0], vmode[1], valid_bpp[i], flags) + == valid_bpp[i]) break; + + if (!valid_bpp[i]) + die("SDL: Can't find a suitable video mode!\n"); + + vmode[2] = valid_bpp[i]; + +#ifdef USE_OGL + if (flags & SDL_OPENGL) + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); +#endif + if (!(screen = SDL_SetVideoMode(vmode[0], vmode[1], vmode[2], flags))) + die("SDL: can't set video mode: %s\n", SDL_GetError()); + + SDL_ShowCursor(0); +} + +#ifdef USE_OGL +static int ogl_init() { - if (!use_yuv) return; + int w = 160, h = 144; + + int texsize = 256; + GLfloat tex_width; + GLfloat tex_height; + + if (use_ogl != 1) return 0; + + sdl_setmode(SDL_OPENGL | SDL_RESIZABLE); + if (screen->format->BitsPerPixel < 15) + return 0; + + ogl_pitch = w * 4; + ogl_framebuf = malloc(ogl_pitch * h); + glViewport(0, 0, vmode[0], vmode[1]); + glMatrixMode (GL_PROJECTION); + glDeleteTextures(1, &ogl_texture); + glGenTextures(1, &ogl_texture); + glBindTexture(GL_TEXTURE_2D, ogl_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + if (use_bilinear) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texsize, texsize, 0, + GL_BGRA_EXT, GL_UNSIGNED_BYTE, 0); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + SDL_GL_SwapBuffers(); + glClear(GL_COLOR_BUFFER_BIT); + glShadeModel(GL_FLAT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDisable(GL_CULL_FACE); + glEnable(GL_TEXTURE_2D); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if (glIsList(ogl_list)) + glDeleteLists(ogl_list, 1); + ogl_list = glGenLists(1); + glNewList(ogl_list, GL_COMPILE); + glBindTexture(GL_TEXTURE_2D, ogl_texture); + glBegin(GL_QUADS); + + tex_width = (GLfloat)(w)/(GLfloat)texsize; + tex_height = (GLfloat)(h)/(GLfloat)texsize; + + glTexCoord2f(0, tex_height); + glVertex2f(-1.0f, -1.0f); + glTexCoord2f(tex_width, tex_height); + glVertex2f(1.0f, -1.0f); + glTexCoord2f(tex_width, 0); + glVertex2f(1.0f, 1.0f); + glTexCoord2f(0, 0); + glVertex2f(-1.0f, 1.0f); + + glEnd(); + glEndList(); + + fb.w = w; + fb.h = h; + fb.pelsize = 4; + fb.pitch = ogl_pitch; + fb.ptr = ogl_framebuf; + fb.cc[0].r = 0; + fb.cc[0].l = 16; + fb.cc[1].r = 0; + fb.cc[1].l = 8; + fb.cc[2].r = 0; + fb.cc[2].l = 0; + + fb.enabled = 1; + fb.dirty = 1; + + ogl = 1; + return 1; +} +#endif + +static void resize_window(int w, int h) +{ + int dw, dh; + + if (w < 160 || h < 144) + return; + + if (keepaspect) { + dw = abs(screen->w - w); + dh = abs(screen->h - h); + if (dw > dh) { + if (w % 2 != 0) w--; + h = (w * 9) / 10; + if (h % 2 != 0) h--; + } else { + if (h % 2 != 0) h--; + w = (h * 10) / 9; + if (w % 2 != 0) w--; + } + } + + vmode[0] = w; + vmode[1] = h; + if (!(screen = SDL_SetVideoMode(w, h, vmode[2], screen->flags))) + die("SDL: can't set video mode: %s\n", SDL_GetError()); + + if (overlay) { + overlay_rect.w = w; + overlay_rect.h = h; + } +#ifdef USE_OGL + if (ogl) { + glViewport(0, 0, w, h); + glFlush(); + glClear(GL_COLOR_BUFFER_BIT); + } +#endif +} + +static int overlay_init() +{ + int i; + + if (use_yuv != 1) return 0; if (use_yuv < 0) if (vmode[0] < 320 || vmode[1] < 288) - return; - - overlay = SDL_CreateYUVOverlay(320, 144, SDL_YUY2_OVERLAY, screen); + return 0; - if (!overlay) return; + sdl_setmode(SDL_RESIZABLE); + + for (i=0; valid_overlay[i]; ++i) { + overlay = SDL_CreateYUVOverlay(320, 144, valid_overlay[i], screen); + if (overlay && overlay->hw_overlay && overlay->planes == 1) + break; + else + SDL_FreeYUVOverlay(overlay); + } - if (!overlay->hw_overlay || overlay->planes > 1) - { + if (valid_overlay[i] == 0) { SDL_FreeYUVOverlay(overlay); overlay = 0; - return; + printf("No suitable hardware-accelerated YUV mode found.\n"); + return 0; } - + SDL_LockYUVOverlay(overlay); + /* Color channels are 0=Y, 1=U, 2=V, 3=Y1 */ + /* Only packed modes are suitable for gnuboy. */ + switch (overlay->format) + { + case SDL_UYVY_OVERLAY: + fb.cc[0].l = 8; + fb.cc[1].l = 0; + fb.cc[2].l = 16; + fb.cc[3].l = 24; + break; + case SDL_YUY2_OVERLAY: + fb.cc[0].l = 0; + fb.cc[1].l = 24; + fb.cc[2].l = 8; + fb.cc[3].l = 16; + break; + case SDL_YVYU_OVERLAY: + fb.cc[0].l = 0; + fb.cc[1].l = 8; + fb.cc[2].l = 24; + fb.cc[3].l = 16; + break; + default: + SDL_UnlockYUVOverlay(overlay); + SDL_FreeYUVOverlay(overlay); + overlay = 0; + printf("Coding bug: Unexpected overlay->format!\n"); + return 0; + } + fb.w = 160; fb.h = 144; fb.pelsize = 4; @@ -137,26 +376,12 @@ static void overlay_init() overlay_rect.w = vmode[0]; overlay_rect.h = vmode[1]; - /* Color channels are 0=Y, 1=U, 2=V, 3=Y1 */ - switch (overlay->format) - { - /* FIXME - support more formats */ - case SDL_YUY2_OVERLAY: - default: - fb.cc[0].l = 0; - fb.cc[1].l = 24; - fb.cc[2].l = 8; - fb.cc[3].l = 16; - break; - } - SDL_UnlockYUVOverlay(overlay); + return 1; } void vid_init() { - int flags; - if (!vmode[0] || !vmode[1]) { int scale = rc_getint("scale"); @@ -165,25 +390,15 @@ void vid_init() vmode[1] = 144 * scale; } - flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE; - - if (fullscreen) - flags |= SDL_FULLSCREEN; - - if (SDL_Init(SDL_INIT_VIDEO)) - die("SDL: Couldn't initialize SDL: %s\n", SDL_GetError()); + joy_init(); - if (!(screen = SDL_SetVideoMode(vmode[0], vmode[1], vmode[2], flags))) - die("SDL: can't set video mode: %s\n", SDL_GetError()); +#ifdef USE_OGL + if (ogl_init()) return; +#endif + if (overlay_init()) return; - SDL_ShowCursor(0); + sdl_setmode(SDL_HWPALETTE); - joy_init(); - - overlay_init(); - - if (fb.yuv) return; - SDL_LockSurface(screen); fb.w = screen->w; @@ -203,7 +418,6 @@ void vid_init() fb.enabled = 1; fb.dirty = 0; - } @@ -275,7 +489,7 @@ void ev_poll() } /* if control reaches here, the axis is centered, - * so just send a release signal if necisary */ + * so just send a release signal if necessary */ if (Xstatus==2) { @@ -332,7 +546,7 @@ void ev_poll() } /* if control reaches here, the axis is centered, - * so just send a release signal if necisary */ + * so just send a release signal if necessary */ if (Ystatus==2) { @@ -363,6 +577,9 @@ void ev_poll() ev.code = K_JOY0+event.jbutton.button; ev_postevent(&ev); break; + case SDL_VIDEORESIZE: + resize_window(event.resize.w, event.resize.h); + break; case SDL_QUIT: exit(1); break; @@ -387,10 +604,14 @@ void vid_preinit() void vid_close() { - if (overlay) - { + if (overlay) { SDL_UnlockYUVOverlay(overlay); SDL_FreeYUVOverlay(overlay); +#ifdef USE_OGL + } else if (ogl) { + free(ogl_framebuf); + ogl_framebuf = NULL; +#endif } else SDL_UnlockSurface(screen); SDL_Quit(); @@ -402,29 +623,45 @@ void vid_settitle(char *title) SDL_WM_SetCaption(title, title); } +/* Careful, since SDL_Lock* can and do change (overlay|screen)->pixels + * behind our back -- they are not merely mutexes! */ void vid_begin() { - if (overlay) - { + if (overlay) { SDL_LockYUVOverlay(overlay); fb.ptr = overlay->pixels[0]; - return; + } else +#ifdef USE_OGL + if (!ogl) +#endif + { + SDL_LockSurface(screen); + fb.ptr = screen->pixels; } - SDL_LockSurface(screen); - fb.ptr = screen->pixels; } void vid_end() { - if (overlay) - { + if (overlay) { SDL_UnlockYUVOverlay(overlay); if (fb.enabled) SDL_DisplayYUVOverlay(overlay, &overlay_rect); return; +#ifdef USE_OGL + } else if (ogl) { + glBindTexture(GL_TEXTURE_2D, ogl_texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, + 160, 144, GL_BGRA_EXT, + GL_UNSIGNED_INT_8_8_8_8_REV, ogl_framebuf); + glCallList(ogl_list); + if (fb.enabled) + SDL_GL_SwapBuffers(); + return; +#endif } SDL_UnlockSurface(screen); - if (fb.enabled) SDL_Flip(screen); + if (fb.enabled) + SDL_Flip(screen); } diff -purN gnuboy-1.0.3/sys/x11/xlib.c gnuboy-1.0.3-nk/sys/x11/xlib.c --- gnuboy-1.0.3/sys/x11/xlib.c Sun Sep 23 21:01:10 2001 +++ gnuboy-1.0.3-nk/sys/x11/xlib.c Tue Oct 26 12:09:27 2004 @@ -60,24 +60,8 @@ static char *x_displayname; static Display *x_display; static int x_screen; -static struct -{ - int bits; - int vc; - int bytes; -} x_vissup[] = -{ - { 8, PseudoColor, 1 }, - { 15, TrueColor, 2 }, - { 16, TrueColor, 2 }, - { 32, TrueColor, 4 }, - { 24, TrueColor, 3 }, - { 0, 0, 0 } -}; - static int x_bits, x_bytes; static Visual *x_vis; -static XVisualInfo x_visinfo; static int x_pseudo; static Colormap x_cmap; static XColor x_ctable[256]; @@ -94,7 +78,7 @@ static GC x_gc; static XSizeHints x_size; static XWMHints x_wmhints; -/*static XClassHint x_class;*/ +static XClassHint x_class; #ifdef USE_XSHM static XShmSegmentInfo x_shm; @@ -247,25 +231,19 @@ void vid_init() die("failed to connect to X display\n"); x_screen = DefaultScreen(x_display); - for (i = 0; x_vissup[i].bits; i++) - { - if (XMatchVisualInfo( - x_display, x_screen, - x_vissup[i].bits, x_vissup[i].vc, &x_visinfo)) - { - if (x_vissup[i].vc == PseudoColor) - x_pseudo = 1; - else - x_pseudo = 0; - x_bits = x_vissup[i].bits; - x_bytes = x_vissup[i].bytes; - break; - } - } - if (!x_bits) die("no suitable X visuals\n"); - x_vis = x_visinfo.visual; + x_vis = DefaultVisual(x_display, x_screen); if (!x_vis) die("X visual is NULL"); + x_cmap = DefaultColormap(x_display, x_screen); + x_bits = DefaultDepth(x_display, x_screen); + x_bytes = x_bits >> 3; + + /* NOTE: This code assumes that all 8-bit color displays are PseudoColor. + * This assumption is correct almost everywhere. */ + + if (x_bytes == 1) + x_pseudo = 1; + if (x_pseudo) { x_cmap = XCreateColormap( @@ -324,8 +302,10 @@ void vid_init() x_wmhints.flags = StateHint | InputHint; XSetWMHints(x_display, x_win, &x_wmhints); - /* FIXME - set X class info stuff (with XSetClassHint)... */ - + x_class.res_name = "xgnuboy"; + x_class.res_class = "xgnuboy"; + XSetClassHint(x_display, x_win, &x_class); + XMapWindow(x_display, x_win); for(;;)