// SDL interface layer // for the Build Engine // by Jonathon Fowler (jonof@edgenetwk.com) // // Use SDL 1.2 or 1.3 from http://www.libsdl.org #include #include #include #include "sdl_inc.h" #include "compat.h" #include "sdlayer.h" #include "cache1d.h" #include "pragmas.h" #include "a.h" #include "build.h" #include "osd.h" #ifdef USE_OPENGL # include "glbuild.h" #endif #if defined __APPLE__ # include "osxbits.h" #elif defined HAVE_GTK2 # include "gtkbits.h" #else int32_t startwin_open(void) { return 0; } int32_t startwin_close(void) { return 0; } int32_t startwin_puts(const char *s) { s=s; return 0; } int32_t startwin_idle(void *s) { s=s; return 0; } int32_t startwin_settitle(const char *s) { s=s; return 0; } #endif #define SURFACE_FLAGS (SDL_SWSURFACE|SDL_HWPALETTE|SDL_HWACCEL) // undefine to restrict windowed resolutions to conventional sizes #define ANY_WINDOWED_SIZE // fix for mousewheel #define MWHEELTICKS 10 static uint32_t mwheelup, mwheeldown; int32_t _buildargc = 1; const char **_buildargv = NULL; extern int32_t app_main(int32_t argc, const char *argv[]); char quitevent=0, appactive=1; // video static SDL_Surface *sdl_surface; int32_t xres=-1, yres=-1, bpp=0, fullscreen=0, bytesperline, imageSize; intptr_t frameplace=0; int32_t lockcount=0; char modechange=1; char offscreenrendering=0; char videomodereset = 0; char nofog=0; static uint16_t sysgamma[3][256]; extern int32_t curbrightness, gammabrightness; #ifdef USE_OPENGL // OpenGL stuff char nogl=0; #endif int32_t vsync=0; // input char inputdevices=0; char keystatus[256], keyfifo[KEYFIFOSIZ], keyfifoplc, keyfifoend; char keyasciififo[KEYFIFOSIZ], keyasciififoplc, keyasciififoend; char remap[256]; int32_t remapinit=0; static char key_names[256][24]; volatile int32_t mousex=0,mousey=0,mouseb=0; int32_t *joyaxis = NULL, joyb=0, *joyhat = NULL; char joyisgamepad=0, joynumaxes=0, joynumbuttons=0, joynumhats=0; int32_t joyaxespresent=0; void(*keypresscallback)(int32_t,int32_t) = 0; void(*mousepresscallback)(int32_t,int32_t) = 0; void(*joypresscallback)(int32_t,int32_t) = 0; #if (SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION < 3) static char keytranslation[SDLK_LAST]; #else static char keytranslation[SDL_NUM_SCANCODES]; #endif static int32_t buildkeytranslationtable(void); //static SDL_Surface * loadtarga(const char *fn); // for loading the icon static SDL_Surface * appicon; static SDL_Surface * loadappicon(void); int32_t wm_msgbox(char *name, char *fmt, ...) { char buf[2048]; va_list va; UNREFERENCED_PARAMETER(name); va_start(va,fmt); vsprintf(buf,fmt,va); va_end(va); #if defined(__APPLE__) return osx_msgbox(name, buf); #elif defined HAVE_GTK2 if (gtkbuild_msgbox(name, buf) >= 0) return 1; #endif puts(buf); puts(" (press Return or Enter to continue)"); getchar(); return 0; } int32_t wm_ynbox(char *name, char *fmt, ...) { char buf[2048]; char c; va_list va; #if (!defined(__APPLE__) && defined(HAVE_GTK2)) int32_t r; #endif UNREFERENCED_PARAMETER(name); va_start(va,fmt); vsprintf(buf,fmt,va); va_end(va); #if defined __APPLE__ return osx_ynbox(name, buf); #elif defined HAVE_GTK2 if ((r = gtkbuild_ynbox(name, buf)) >= 0) return r; #endif puts(buf); puts(" (type 'Y' or 'N', and press Return or Enter to continue)"); do c = getchar(); while (c != 'Y' && c != 'y' && c != 'N' && c != 'n'); if (c == 'Y' || c == 'y') return 1; return 0; } void wm_setapptitle(char *name) { if (name) { Bstrncpy(apptitle, name, sizeof(apptitle)-1); apptitle[ sizeof(apptitle)-1 ] = 0; } SDL_WM_SetCaption(apptitle, NULL); startwin_settitle(apptitle); } // // // --------------------------------------- // // System // // --------------------------------------- // // int32_t main(int32_t argc, char *argv[]) { int32_t r; char *argp; FILE *fp; nedcreatepool(SYSTEM_POOL_SIZE, -1); // atexit(neddestroysyspool); buildkeytranslationtable(); #ifdef HAVE_GTK2 gtkbuild_init(&argc, &argv); #endif startwin_open(); _buildargc = argc; _buildargv = (const char**)argv; // pipe standard outputs to files if ((argp = Bgetenv("BUILD_LOGSTDOUT")) != NULL) if (!Bstrcasecmp(argp, "TRUE")) { fp = freopen("stdout.txt", "w", stdout); if (!fp) { fp = fopen("stdout.txt", "w"); } if (fp) setvbuf(fp, 0, _IONBF, 0); *stdout = *fp; *stderr = *fp; } #if defined(USE_OPENGL) && defined(POLYMOST) if ((argp = Bgetenv("BUILD_NOFOG")) != NULL) nofog = Batol(argp); #endif baselayer_init(); r = app_main(_buildargc, _buildargv); startwin_close(); #ifdef HAVE_GTK2 gtkbuild_exit(r); #endif return r; } #if defined(USE_OPENGL) && defined(POLYMOST) void setvsync(int32_t sync) { if (vsync == sync) return; vsync = sync; resetvideomode(); if (setgamemode(fullscreen,xdim,ydim,bpp)) OSD_Printf("restartvid: Reset failed...\n"); } #endif static void attach_debugger_here(void){} static void sighandler(int signum) { // if (signum==SIGSEGV) { SDL_WM_GrabInput(SDL_GRAB_OFF); SDL_ShowCursor(SDL_ENABLE); attach_debugger_here(); uninitsystem(); exit(1); } } // // initsystem() -- init SDL systems // int32_t initsystem(void) { /* #ifdef DEBUGGINGAIDS const SDL_VideoInfo *vid; #endif */ const SDL_version *linked = SDL_Linked_Version(); SDL_version compiled; char drvname[32]; SDL_VERSION(&compiled); initprintf("Initializing SDL system interface " "(compiled against SDL version %d.%d.%d, found version %d.%d.%d)\n", compiled.major, compiled.minor, compiled.patch, linked->major, linked->minor, linked->patch); if (SDL_VERSIONNUM(linked->major,linked->minor,linked->patch) < SDL_REQUIREDVERSION) { /*reject running under SDL versions older than what is stated in sdl_inc.h */ initprintf("You need at least v%d.%d.%d of SDL to run this game\n",SDL_MIN_X,SDL_MIN_Y,SDL_MIN_Z); return -1; } if (SDL_Init(SDL_INIT_VIDEO //| SDL_INIT_TIMER #ifdef NOSDLPARACHUTE | SDL_INIT_NOPARACHUTE #endif )) { initprintf("Initialization failed! (%s)\n", SDL_GetError()); return -1; } signal(SIGSEGV, sighandler); signal(SIGABRT, sighandler); signal(SIGFPE, sighandler); atexit(uninitsystem); frameplace = 0; lockcount = 0; #ifdef USE_OPENGL if (loadgldriver(getenv("BUILD_GLDRV"))) { initprintf("Failed loading OpenGL driver. GL modes will be unavailable.\n"); nogl = 1; } #endif #ifndef __APPLE__ //icon = loadtarga("icon.tga"); appicon = loadappicon(); if (appicon) SDL_WM_SetIcon(appicon, 0); #endif if (SDL_VideoDriverName(drvname, 32)) initprintf("Using \"%s\" video driver\n", drvname); /* // dump a quick summary of the graphics hardware #ifdef DEBUGGINGAIDS vid = SDL_GetVideoInfo(); initprintf("Video device information:\n"); initprintf(" Can create hardware surfaces? %s\n", (vid->hw_available)?"Yes":"No"); initprintf(" Window manager available? %s\n", (vid->wm_available)?"Yes":"No"); initprintf(" Accelerated hardware blits? %s\n", (vid->blit_hw)?"Yes":"No"); initprintf(" Accelerated hardware colourkey blits? %s\n", (vid->blit_hw_CC)?"Yes":"No"); initprintf(" Accelerated hardware alpha blits? %s\n", (vid->blit_hw_A)?"Yes":"No"); initprintf(" Accelerated software blits? %s\n", (vid->blit_sw)?"Yes":"No"); initprintf(" Accelerated software colourkey blits? %s\n", (vid->blit_sw_CC)?"Yes":"No"); initprintf(" Accelerated software alpha blits? %s\n", (vid->blit_sw_A)?"Yes":"No"); initprintf(" Accelerated colour fills? %s\n", (vid->blit_fill)?"Yes":"No"); initprintf(" Total video memory: %dKB\n", vid->video_mem); #endif */ return 0; } // // uninitsystem() -- uninit SDL systems // void uninitsystem(void) { uninitinput(); uninitmouse(); uninittimer(); if (appicon) SDL_FreeSurface(appicon); SDL_Quit(); #ifdef USE_OPENGL unloadgldriver(); #endif } // // initprintf() -- prints a string to the intitialization window // void initprintf(const char *f, ...) { va_list va; char buf[1024]; static char dabuf[1024]; va_start(va, f); Bvsnprintf(buf, 1024, f, va); va_end(va); OSD_Printf(buf); Bprintf("%s", buf); if (Bstrlen(dabuf) + Bstrlen(buf) > 1022) { startwin_puts(dabuf); Bmemset(dabuf, 0, sizeof(dabuf)); } Bstrcat(dabuf,buf); if (flushlogwindow || Bstrlen(dabuf) > 768) { startwin_puts(dabuf); startwin_idle(NULL); Bmemset(dabuf, 0, sizeof(dabuf)); } } // // debugprintf() -- prints a debug string to stderr // void debugprintf(const char *f, ...) { #ifdef DEBUGGINGAIDS va_list va; va_start(va,f); Bvfprintf(stderr, f, va); va_end(va); #else UNREFERENCED_PARAMETER(f); #endif } // // // --------------------------------------- // // All things Input // // --------------------------------------- // // static char mouseacquired=0,moustat=0; // static int32_t joyblast=0; static SDL_Joystick *joydev = NULL; // // initinput() -- init input system // int32_t initinput(void) { int32_t i,j; #ifdef __APPLE__ // force OS X to operate in >1 button mouse mode so that LMB isn't adulterated if (!getenv("SDL_HAS3BUTTONMOUSE")) putenv("SDL_HAS3BUTTONMOUSE=1"); #endif if (!remapinit) for (i=0; i<256; i++) remap[i]=i; remapinit=1; if (SDL_EnableKeyRepeat(250, 30)) // doesn't do anything in 1.3 initprintf("Error enabling keyboard repeat.\n"); inputdevices = 1|2; // keyboard (1) and mouse (2) mouseacquired = 0; SDL_EnableUNICODE(1); // let's hope this doesn't hit us too hard memset(key_names,0,sizeof(key_names)); #if (SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION < 3) for (i=0; i= 256) return NULL; return key_names[num]; } const char *getjoyname(int32_t what, int32_t num) { static char tmp[64]; switch (what) { case 0: // axis if ((unsigned)num > (unsigned)joynumaxes) return NULL; Bsprintf(tmp,"Axis %d",num); return (char *)tmp; case 1: // button if ((unsigned)num > (unsigned)joynumbuttons) return NULL; Bsprintf(tmp,"Button %d",num); return (char *)tmp; case 2: // hat if ((unsigned)num > (unsigned)joynumhats) return NULL; Bsprintf(tmp,"Hat %d",num); return (char *)tmp; default: return NULL; } } // // bgetchar, bkbhit, bflushchars -- character-based input functions // char bgetchar(void) { char c; if (keyasciififoplc == keyasciififoend) return 0; c = keyasciififo[keyasciififoplc]; keyasciififoplc = ((keyasciififoplc+1)&(KEYFIFOSIZ-1)); return c; } int32_t bkbhit(void) { return (keyasciififoplc != keyasciififoend); } void bflushchars(void) { keyasciififoplc = keyasciififoend = 0; } // // set{key|mouse|joy}presscallback() -- sets a callback which gets notified when keys are pressed // void setkeypresscallback(void(*callback)(int32_t, int32_t)) { keypresscallback = callback; } void setmousepresscallback(void(*callback)(int32_t, int32_t)) { mousepresscallback = callback; } void setjoypresscallback(void(*callback)(int32_t, int32_t)) { joypresscallback = callback; } // // initmouse() -- init mouse input // int32_t initmouse(void) { moustat=1; grabmouse(1); // FIXME - SA return 0; } // // uninitmouse() -- uninit mouse input // void uninitmouse(void) { grabmouse(0); moustat=0; } // // grabmouse() -- show/hide mouse cursor // void grabmouse(char a) { if (appactive && moustat) { if (a != mouseacquired) { // #ifndef DEBUGGINGAIDS #if 1 SDL_GrabMode g; g = SDL_WM_GrabInput(a ? SDL_GRAB_ON : SDL_GRAB_OFF); mouseacquired = (g == SDL_GRAB_ON); SDL_ShowCursor(mouseacquired ? SDL_DISABLE : SDL_ENABLE); #else mouseacquired = a; #endif } } else { mouseacquired = a; } mousex = mousey = 0; } // // readmousexy() -- return mouse motion information // void readmousexy(int32_t *x, int32_t *y) { if (!mouseacquired || !appactive || !moustat) { *x = *y = 0; return; } *x = mousex; *y = mousey; mousex = mousey = 0; } // // readmousebstatus() -- return mouse button information // void readmousebstatus(int32_t *b) { if (!mouseacquired || !appactive || !moustat) *b = 0; else *b = mouseb; } // // setjoydeadzone() -- sets the dead and saturation zones for the joystick // void setjoydeadzone(int32_t axis, uint16_t dead, uint16_t satur) { UNREFERENCED_PARAMETER(axis); UNREFERENCED_PARAMETER(dead); UNREFERENCED_PARAMETER(satur); } // // getjoydeadzone() -- gets the dead and saturation zones for the joystick // void getjoydeadzone(int32_t axis, uint16_t *dead, uint16_t *satur) { UNREFERENCED_PARAMETER(axis); *dead = *satur = 0; } // // releaseallbuttons() // void releaseallbuttons(void) {} // // // --------------------------------------- // // All things Timer // Ken did this // // --------------------------------------- // // static Uint32 timerfreq=0; static Uint32 timerlastsample=0; Uint32 timerticspersec=0; static void(*usertimercallback)(void) = NULL; // // inittimer() -- initialize timer // int32_t inittimer(int32_t tickspersecond) { if (timerfreq) return 0; // already installed // initprintf("Initializing timer\n"); timerfreq = 1000; timerticspersec = tickspersecond; timerlastsample = SDL_GetTicks() * timerticspersec / timerfreq; usertimercallback = NULL; return 0; } // // uninittimer() -- shut down timer // void uninittimer(void) { if (!timerfreq) return; timerfreq=0; } // // sampletimer() -- update totalclock // void sampletimer(void) { Uint32 i; int32_t n; if (!timerfreq) return; i = SDL_GetTicks(); n = (int32_t)(i * timerticspersec / timerfreq) - timerlastsample; if (n>0) { totalclock += n; timerlastsample += n; } if (usertimercallback) for (; n>0; n--) usertimercallback(); } // // getticks() -- returns the sdl ticks count // uint32_t getticks(void) { return (uint32_t)SDL_GetTicks(); } // // gettimerfreq() -- returns the number of ticks per second the timer is configured to generate // int32_t gettimerfreq(void) { return timerticspersec; } // // installusertimercallback() -- set up a callback function to be called when the timer is fired // void(*installusertimercallback(void(*callback)(void)))(void) { void(*oldtimercallback)(void); oldtimercallback = usertimercallback; usertimercallback = callback; return oldtimercallback; } // // // --------------------------------------- // // All things Video // // --------------------------------------- // // // // getvalidmodes() -- figure out what video modes are available // static int32_t sortmodes(const struct validmode_t *a, const struct validmode_t *b) { int32_t x; if ((x = a->fs - b->fs) != 0) return x; if ((x = a->bpp - b->bpp) != 0) return x; if ((x = a->xdim - b->xdim) != 0) return x; if ((x = a->ydim - b->ydim) != 0) return x; return 0; } static char modeschecked=0; void getvalidmodes(void) { static int32_t cdepths[] = { 8, #ifdef USE_OPENGL 16,24,32, #endif 0 }; static int32_t defaultres[][2] = { {1280,1024} ,{1280,960},{1152,864},{1024,768},{800,600},{640,480}, {640,400},{512,384},{480,360},{400,300},{320,240},{320,200},{0,0} }; SDL_Rect **modes; #if (SDL_MAJOR_VERSION > 1 || SDL_MINOR_VERSION > 2) SDL_PixelFormat pf = { NULL, 8, 1, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; #else SDL_PixelFormat pf = { NULL, 8, 1, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0 }; #endif int32_t i, j, maxx=0, maxy=0; if (modeschecked) return; validmodecnt=0; // initprintf("Detecting video modes:\n"); #define ADDMODE(x,y,c,f) if (validmodecnt 8) continue; #endif pf.BitsPerPixel = cdepths[j]; pf.BytesPerPixel = cdepths[j] >> 3; modes = SDL_ListModes(&pf, SURFACE_FLAGS #if (SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION < 3) | SDL_FULLSCREEN // not implemented/working in SDL 1.3 SDL_compat.c #endif ); if (modes == (SDL_Rect **)0) { if (cdepths[j] > 8) cdepths[j] = -1; continue; } if (modes == (SDL_Rect **)-1) { for (i=0; defaultres[i][0]; i++) ADDMODE(defaultres[i][0],defaultres[i][1],cdepths[j],1) } else { for (i=0; modes[i]; i++) { if ((modes[i]->w > MAXXDIM) || (modes[i]->h > MAXYDIM)) continue; ADDMODE(modes[i]->w, modes[i]->h, cdepths[j], 1) if ((modes[i]->w > maxx) && (modes[i]->h > maxy)) { maxx = modes[i]->w; maxy = modes[i]->h; } } } } if (maxx == 0 && maxy == 0) { initprintf("No fullscreen modes available!\n"); maxx = MAXXDIM; maxy = MAXYDIM; } // add windowed modes next for (j=0; cdepths[j]; j++) { #ifdef USE_OPENGL if (nogl && cdepths[j] > 8) continue; #endif if (cdepths[j] < 0) continue; for (i=0; defaultres[i][0]; i++) CHECK(defaultres[i][0],defaultres[i][1]) ADDMODE(defaultres[i][0],defaultres[i][1],cdepths[j],0) } #undef CHECK #undef ADDMODE qsort((void*)validmode, validmodecnt, sizeof(struct validmode_t), (int32_t(*)(const void*,const void*))sortmodes); modeschecked=1; } // // checkvideomode() -- makes sure the video mode passed is legal // int32_t checkvideomode(int32_t *x, int32_t *y, int32_t c, int32_t fs, int32_t forced) { int32_t i, nearest=-1, dx, dy, odx=9999, ody=9999; getvalidmodes(); if (c>8 #ifdef USE_OPENGL && nogl #endif ) return -1; // fix up the passed resolution values to be multiples of 8 // and at least 320x200 or at most MAXXDIMxMAXYDIM if (*x < 320) *x = 320; if (*y < 200) *y = 200; if (*x > MAXXDIM) *x = MAXXDIM; if (*y > MAXYDIM) *y = MAXYDIM; // *x &= 0xfffffff8l; for (i=0; i 8 && sdl_surface) polymost_glreset(); #endif // restore gamma before we change video modes if it was changed if (sdl_surface && gammabrightness) { SDL_SetGammaRamp(sysgamma[0], sysgamma[1], sysgamma[2]); gammabrightness = 0; // redetect on next mode switch } #if defined(USE_OPENGL) if (c > 8) { int32_t i, j, multisamplecheck = (glmultisample > 0); struct { SDL_GLattr attr; int32_t value; } attributes[] = { #if 0 { SDL_GL_RED_SIZE, 8 }, { SDL_GL_GREEN_SIZE, 8 }, { SDL_GL_BLUE_SIZE, 8 }, { SDL_GL_ALPHA_SIZE, 8 }, { SDL_GL_BUFFER_SIZE, c }, { SDL_GL_STENCIL_SIZE, 0 }, { SDL_GL_ACCUM_RED_SIZE, 0 }, { SDL_GL_ACCUM_GREEN_SIZE, 0 }, { SDL_GL_ACCUM_BLUE_SIZE, 0 }, { SDL_GL_ACCUM_ALPHA_SIZE, 0 }, { SDL_GL_DEPTH_SIZE, 24 }, #endif { SDL_GL_DOUBLEBUFFER, 1 }, { SDL_GL_MULTISAMPLEBUFFERS, glmultisample > 0 }, { SDL_GL_MULTISAMPLESAMPLES, glmultisample }, { SDL_GL_STENCIL_SIZE, 1 }, #if (SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION < 3) { SDL_GL_SWAP_CONTROL, vsync }, #endif }; if (nogl) return -1; initprintf("Setting video mode %dx%d (%d-bpp %s)\n", x,y,c, ((fs&1) ? "fullscreen" : "windowed")); do { for (i=0; i < (int32_t)(sizeof(attributes)/sizeof(attributes[0])); i++) { j = attributes[i].value; if (!multisamplecheck && (attributes[i].attr == SDL_GL_MULTISAMPLEBUFFERS || attributes[i].attr == SDL_GL_MULTISAMPLESAMPLES) ) { j = 0; } SDL_GL_SetAttribute(attributes[i].attr, j); } /* HACK: changing SDL GL attribs only works before surface creation, so we have to create a new surface in a different format first to force the surface we WANT to be recreated instead of reused. */ #if (SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION < 3) if (vsync != ovsync) { if (sdl_surface) { SDL_FreeSurface(sdl_surface); sdl_surface = SDL_SetVideoMode(1, 1, 8, SDL_NOFRAME | SURFACE_FLAGS | ((fs&1)?SDL_FULLSCREEN:0)); SDL_FreeSurface(sdl_surface); } ovsync = vsync; } #endif sdl_surface = SDL_SetVideoMode(x, y, c, SDL_OPENGL | ((fs&1)?SDL_FULLSCREEN:0)); if (!sdl_surface) { if (multisamplecheck) { initprintf("Multisample mode not possible. Retrying without multisampling.\n"); glmultisample = 0; continue; } initprintf("Unable to set video mode!\n"); return -1; } } while (multisamplecheck--); } else #endif { initprintf("Setting video mode %dx%d (%d-bpp %s)\n", x,y,c, ((fs&1) ? "fullscreen" : "windowed")); sdl_surface = SDL_SetVideoMode(x, y, c, SURFACE_FLAGS | ((fs&1)?SDL_FULLSCREEN:0)); if (!sdl_surface) { initprintf("Unable to set video mode!\n"); return -1; } } #if 0 { char flags[512] = ""; #define FLAG(x,y) if ((sdl_surface->flags & x) == x) { strcat(flags, y); strcat(flags, " "); } FLAG(SDL_HWSURFACE, "HWSURFACE") else FLAG(SDL_SWSURFACE, "SWSURFACE") FLAG(SDL_ASYNCBLIT, "ASYNCBLIT") FLAG(SDL_ANYFORMAT, "ANYFORMAT") FLAG(SDL_HWPALETTE, "HWPALETTE") FLAG(SDL_DOUBLEBUF, "DOUBLEBUF") FLAG(SDL_FULLSCREEN, "FULLSCREEN") FLAG(SDL_OPENGL, "OPENGL") FLAG(SDL_OPENGLBLIT, "OPENGLBLIT") FLAG(SDL_RESIZABLE, "RESIZABLE") FLAG(SDL_HWACCEL, "HWACCEL") FLAG(SDL_SRCCOLORKEY, "SRCCOLORKEY") FLAG(SDL_RLEACCEL, "RLEACCEL") FLAG(SDL_SRCALPHA, "SRCALPHA") FLAG(SDL_PREALLOC, "PREALLOC") #undef FLAG initprintf("SDL Surface flags: %s\n", flags); } #endif { //static char t[384]; //sprintf(t, "%s (%dx%d %s)", apptitle, x, y, ((fs) ? "fullscreen" : "windowed")); SDL_WM_SetCaption(apptitle, 0); } #ifdef USE_OPENGL if (c > 8) { char *p,*p2,*p3; polymost_glreset(); bglEnable(GL_TEXTURE_2D); bglShadeModel(GL_SMOOTH); //GL_FLAT bglClearColor(0,0,0,0.5); //Black Background bglHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); //Use FASTEST for ortho! bglHint(GL_LINE_SMOOTH_HINT,GL_NICEST); bglDisable(GL_DITHER); glinfo.vendor = (const char *)bglGetString(GL_VENDOR); glinfo.renderer = (const char *)bglGetString(GL_RENDERER); glinfo.version = (const char *)bglGetString(GL_VERSION); glinfo.extensions = (const char *)bglGetString(GL_EXTENSIONS); #ifdef POLYMER if (!Bstrcmp(glinfo.vendor,"ATI Technologies Inc.")) { pr_ati_fboworkaround = 1; initprintf("Enabling ATI FBO color attachment workaround.\n"); if (!Bstrncmp(glinfo.renderer,"Radeon X1", 9)) { pr_ati_nodepthoffset = 1; initprintf("Enabling ATI R520 polygon offset workaround.\n"); } else pr_ati_nodepthoffset = 0; } else pr_ati_fboworkaround = 0; #endif glinfo.maxanisotropy = 1.0; glinfo.bgra = 0; glinfo.texcompr = 0; // process the extensions string and flag stuff we recognize p = Bstrdup(glinfo.extensions); p3 = p; while ((p2 = Bstrtoken(p3==p?p:NULL, " ", (char**)&p3, 1)) != NULL) { if (!Bstrcmp(p2, "GL_EXT_texture_filter_anisotropic")) { // supports anisotropy. get the maximum anisotropy level bglGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glinfo.maxanisotropy); } else if (!Bstrcmp(p2, "GL_EXT_texture_edge_clamp") || !Bstrcmp(p2, "GL_SGIS_texture_edge_clamp")) { // supports GL_CLAMP_TO_EDGE or GL_CLAMP_TO_EDGE_SGIS glinfo.clamptoedge = 1; } else if (!Bstrcmp(p2, "GL_EXT_bgra")) { // support bgra textures glinfo.bgra = 1; } else if (!Bstrcmp(p2, "GL_ARB_texture_compression")) { // support texture compression glinfo.texcompr = 1; } else if (!Bstrcmp(p2, "GL_ARB_texture_non_power_of_two")) { // support non-power-of-two texture sizes glinfo.texnpot = 1; } else if (!Bstrcmp(p2, "WGL_3DFX_gamma_control")) { // 3dfx cards have issues with fog nofog = 1; if (!(warnonce&1)) initprintf("3dfx card detected: OpenGL fog disabled\n"); warnonce |= 1; } else if (!Bstrcmp(p2, "GL_ARB_multisample")) { // supports multisampling glinfo.multisample = 1; } else if (!Bstrcmp(p2, "GL_NV_multisample_filter_hint")) { // supports nvidia's multisample hint extension glinfo.nvmultisamplehint = 1; } else if (!Bstrcmp((char *)p2, "GL_ARB_fragment_program")) { glinfo.arbfp = 1; } else if (!Bstrcmp((char *)p2, "GL_ARB_depth_texture")) { glinfo.depthtex = 1; } else if (!Bstrcmp((char *)p2, "GL_ARB_shadow")) { glinfo.shadow = 1; } else if (!Bstrcmp((char *)p2, "GL_EXT_framebuffer_object")) { glinfo.fbos = 1; } else if (!Bstrcmp((char *)p2, "GL_NV_texture_rectangle") || !Bstrcmp((char *)p2, "GL_EXT_texture_rectangle")) { glinfo.rect = 1; } else if (!Bstrcmp((char *)p2, "GL_ARB_multitexture")) { glinfo.multitex = 1; } else if (!Bstrcmp((char *)p2, "GL_ARB_texture_env_combine")) { glinfo.envcombine = 1; } else if (!Bstrcmp((char *)p2, "GL_ARB_vertex_buffer_object")) { glinfo.vbos = 1; } else if (!Bstrcmp((char *)p2, "GL_EXT_gpu_shader4")) { glinfo.sm4 = 1; } else if (!Bstrcmp((char *)p2, "GL_ARB_occlusion_query")) { glinfo.occlusionqueries = 1; } else if (!Bstrcmp((char *)p2, "GL_ARB_shader_objects")) { glinfo.glsl = 1; } } Bfree(p); if (!glinfo.dumped) { int32_t oldbpp = bpp; bpp = 32; osdcmd_glinfo(NULL); glinfo.dumped = 1; bpp = oldbpp; } } #endif xres = x; yres = y; bpp = c; fullscreen = fs; //bytesperline = sdl_surface->pitch; //imageSize = bytesperline*yres; numpages = c>8?2:1; frameplace = 0; lockcount = 0; modechange=1; videomodereset = 0; OSD_ResizeDisplay(xres,yres); // save the current system gamma to determine if gamma is available if (!gammabrightness) { // float f = 1.0 + ((float)curbrightness / 10.0); if (SDL_GetGammaRamp(sysgamma[0], sysgamma[1], sysgamma[2]) >= 0) gammabrightness = 1; // see if gamma really is working by trying to set the brightness if (gammabrightness && setgamma() < 0) gammabrightness = 0; // nope } // setpalettefade will set the palette according to whether gamma worked setpalettefade(palfadergb.r, palfadergb.g, palfadergb.b, palfadedelta); //if (c==8) setpalette(0,256,0); //baselayer_onvideomodechange(c>8); if (regrab) grabmouse(1); return 0; } // // resetvideomode() -- resets the video system // void resetvideomode(void) { videomodereset = 1; modeschecked = 0; } // // begindrawing() -- locks the framebuffer for drawing // void begindrawing(void) { int32_t i,j; if (bpp > 8) { if (offscreenrendering) return; frameplace = 0; bytesperline = 0; imageSize = 0; modechange = 0; return; } // lock the frame if (lockcount++ > 0) return; if (offscreenrendering) return; if (SDL_MUSTLOCK(sdl_surface)) SDL_LockSurface(sdl_surface); frameplace = (intptr_t)sdl_surface->pixels; if (sdl_surface->pitch != bytesperline || modechange) { bytesperline = sdl_surface->pitch; imageSize = bytesperline*yres; setvlinebpl(bytesperline); j = 0; for (i=0; i<=ydim; i++) ylookup[i] = j, j += bytesperline; modechange=0; } } // // enddrawing() -- unlocks the framebuffer // void enddrawing(void) { if (bpp > 8) { if (!offscreenrendering) frameplace = 0; return; } if (!frameplace) return; if (lockcount > 1) { lockcount--; return; } if (!offscreenrendering) frameplace = 0; if (lockcount == 0) return; lockcount = 0; if (offscreenrendering) return; if (SDL_MUSTLOCK(sdl_surface)) SDL_UnlockSurface(sdl_surface); } // // showframe() -- update the display // void showframe(int32_t w) { // int32_t i,j; UNREFERENCED_PARAMETER(w); #ifdef USE_OPENGL if (bpp > 8) { if (palfadedelta) { bglMatrixMode(GL_PROJECTION); bglPushMatrix(); bglLoadIdentity(); bglMatrixMode(GL_MODELVIEW); bglPushMatrix(); bglLoadIdentity(); bglDisable(GL_DEPTH_TEST); bglDisable(GL_ALPHA_TEST); bglDisable(GL_TEXTURE_2D); bglEnable(GL_BLEND); bglColor4ub(palfadergb.r, palfadergb.g, palfadergb.b, palfadedelta); bglBegin(GL_QUADS); bglVertex2i(-1, -1); bglVertex2i(1, -1); bglVertex2i(1, 1); bglVertex2i(-1, 1); bglEnd(); bglDisable(GL_BLEND); bglMatrixMode(GL_MODELVIEW); bglPopMatrix(); bglMatrixMode(GL_PROJECTION); bglPopMatrix(); } SDL_GL_SwapBuffers(); return; } #endif if (offscreenrendering) return; if (lockcount) { printf("Frame still locked %d times when showframe() called.\n", lockcount); while (lockcount) enddrawing(); } SDL_Flip(sdl_surface); } // // setpalette() -- set palette values // int32_t setpalette(int32_t start, int32_t num) { SDL_Color pal[256]; int32_t i,n; if (bpp > 8) return 0; // no palette in opengl copybuf(curpalettefaded, pal, 256); for (i=start, n=num; n>0; i++, n--) curpalettefaded[i].f = pal[i].unused = 0; //return SDL_SetPalette(sdl_surface, SDL_LOGPAL|SDL_PHYSPAL, pal, 0, 256); return sdl_surface ? SDL_SetColors(sdl_surface, pal, 0, 256) : 0; } // // getpalette() -- get palette values // /* int32_t getpalette(int32_t start, int32_t num, char *dapal) { int32_t i; SDL_Palette *pal; // we shouldn't need to lock the surface to get the palette pal = sdl_surface->format->palette; for (i=num; i>0; i--, start++) { dapal[0] = pal->colors[start].b >> 2; dapal[1] = pal->colors[start].g >> 2; dapal[2] = pal->colors[start].r >> 2; dapal += 4; } return 1; } */ // // setgamma // int32_t setgamma(void) { int32_t i; uint16_t gammaTable[768]; float gamma = max(0.1f,min(4.f,vid_gamma)); float contrast = max(0.1f,min(3.f,vid_contrast)); float bright = max(-0.8f,min(0.8f,vid_brightness)); double invgamma = 1 / gamma; double norm = pow(255., invgamma - 1); // This formula is taken from Doomsday for (i = 0; i < 256; i++) { double val = i * contrast - (contrast - 1) * 127; if (gamma != 1) val = pow(val, invgamma) / norm; val += bright * 128; gammaTable[i] = gammaTable[i + 256] = gammaTable[i + 512] = (uint16_t)max(0.f,(double)min(0xffff,val*256)); } return SDL_SetGammaRamp(&gammaTable[0],&gammaTable[256],&gammaTable[512]); } #ifndef __APPLE__ extern struct sdlappicon sdlappicon; static SDL_Surface * loadappicon(void) { SDL_Surface *surf; surf = SDL_CreateRGBSurfaceFrom((void*)sdlappicon.pixels, sdlappicon.width, sdlappicon.height, 32, sdlappicon.width*4, 0xffl,0xff00l,0xff0000l,0xff000000l); return surf; } #endif // // // --------------------------------------- // // Miscellany // // --------------------------------------- // // // // handleevents() -- process the SDL message queue // returns !0 if there was an important event worth checking (like quitting) // int32_t handleevents(void) { int32_t code, rv=0, j; SDL_Event ev; #define SetKey(key,state) { \ keystatus[remap[key]] = state; \ if (state) { \ keyfifo[keyfifoend] = remap[key]; \ keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = state; \ keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1)); \ } \ } while (SDL_PollEvent(&ev)) { switch (ev.type) { #if (SDL_MAJOR_VERSION > 1 || SDL_MINOR_VERSION > 2) case SDL_TEXTINPUT: j = 0; do { code = ev.text.text[j]; if (code != scantoasc[OSD_OSDKey()] && ((keyasciififoend+1)&(KEYFIFOSIZ-1)) != keyasciififoplc) { if (OSD_HandleChar(code)) { keyasciififo[keyasciififoend] = code; keyasciififoend = ((keyasciififoend+1)&(KEYFIFOSIZ-1)); } } } while (j < SDL_TEXTINPUTEVENT_TEXT_SIZE && ev.text.text[++j]); break; case SDL_KEYDOWN: case SDL_KEYUP: code = keytranslation[ev.key.keysym.scancode]; // initprintf("got key %d, %d\n",ev.key.keysym.scancode,code); // hook in the osd if (OSD_HandleScanCode(code, (ev.key.type == SDL_KEYDOWN)) == 0) break; if (ev.key.type == SDL_KEYDOWN) { if (!keystatus[code]) { SetKey(code, 1); if (keypresscallback) keypresscallback(code, 1); } } else { SetKey(code, 0); if (keypresscallback) keypresscallback(code, 0); } break; case SDL_WINDOWEVENT: switch (ev.window.event) { case SDL_WINDOWEVENT_FOCUS_GAINED: appactive = 1; #ifndef DEBUGGINGAIDS if (mouseacquired && moustat) { SDL_WM_GrabInput(SDL_GRAB_ON); SDL_ShowCursor(SDL_DISABLE); } #endif break; case SDL_WINDOWEVENT_FOCUS_LOST: appactive = 0; #ifndef DEBUGGINGAIDS if (mouseacquired && moustat) { SDL_WM_GrabInput(SDL_GRAB_OFF); SDL_ShowCursor(SDL_ENABLE); } #endif break; } break; /* case SDL_MOUSEWHEEL: initprintf("wheel y %d\n",ev.wheel.y); if (ev.wheel.y > 0) { mwheelup = totalclock; mouseb |= 16; if (mousepresscallback) mousepresscallback(5, 1); } if (ev.wheel.y < 0) { mwheeldown = totalclock; mouseb |= 32; if (mousepresscallback) mousepresscallback(6, 1); } break; */ #else case SDL_KEYDOWN: case SDL_KEYUP: code = keytranslation[ev.key.keysym.sym]; if (code != OSD_OSDKey() && ev.key.keysym.unicode != 0 && ev.key.type == SDL_KEYDOWN && (ev.key.keysym.unicode & 0xff80) == 0 && ((keyasciififoend+1)&(KEYFIFOSIZ-1)) != keyasciififoplc) { if (OSD_HandleChar(ev.key.keysym.unicode & 0x7f)) { keyasciififo[keyasciififoend] = ev.key.keysym.unicode & 0x7f; keyasciififoend = ((keyasciififoend+1)&(KEYFIFOSIZ-1)); } } // hook in the osd if (OSD_HandleScanCode(code, (ev.key.type == SDL_KEYDOWN)) == 0) break; if (ev.key.type == SDL_KEYDOWN) { if (!keystatus[code]) { SetKey(code, 1); if (keypresscallback) keypresscallback(code, 1); } } else { SetKey(code, 0); if (keypresscallback) keypresscallback(code, 0); } break; case SDL_ACTIVEEVENT: if (ev.active.state & SDL_APPINPUTFOCUS) { appactive = ev.active.gain; #ifndef DEBUGGINGAIDS if (mouseacquired && moustat) { if (appactive) { SDL_WM_GrabInput(SDL_GRAB_ON); SDL_ShowCursor(SDL_DISABLE); } else { SDL_WM_GrabInput(SDL_GRAB_OFF); SDL_ShowCursor(SDL_ENABLE); } } #endif rv=-1; } break; #endif case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: switch (ev.button.button) { // some of these get reordered to match winlayer default: j = -1; break; case SDL_BUTTON_LEFT: j = 0; break; case SDL_BUTTON_RIGHT: j = 1; break; case SDL_BUTTON_MIDDLE: j = 2; break; case SDL_BUTTON_WHEELUP: case SDL_BUTTON_WHEELDOWN: j = ev.button.button; break; } if (j<0) break; if (ev.button.state == SDL_PRESSED) { if (ev.button.button == SDL_BUTTON_WHEELUP) { mwheelup = totalclock; } if (ev.button.button == SDL_BUTTON_WHEELDOWN) { mwheeldown = totalclock; } mouseb |= (1< #elif defined __linux || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ # include #endif void makeasmwriteable(void) { #ifndef ENGINE_USING_A_C extern int32_t dep_begin, dep_end; # if defined _WIN32 DWORD oldprot; if (!VirtualProtect((LPVOID)&dep_begin, (SIZE_T)&dep_end - (SIZE_T)&dep_begin, PAGE_EXECUTE_READWRITE, &oldprot)) { initprint("Error making code writeable\n"); return; } # elif defined __linux || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ int32_t pagesize; size_t dep_begin_page; pagesize = sysconf(_SC_PAGE_SIZE); if (pagesize == -1) { initprintf("Error getting system page size\n"); return; } dep_begin_page = ((size_t)&dep_begin) & ~(pagesize-1); if (mprotect((void *)dep_begin_page, (size_t)&dep_end - dep_begin_page, PROT_READ|PROT_WRITE) < 0) { initprintf("Error making code writeable (errno=%d)\n", errno); return; } # else # error "Don't know how to unprotect the self-modifying assembly on this platform!" # endif #endif }