/*************************************************************************** gui.cpp -- gui ------------------- created : Fri Aug 13 22:01:33 CEST 1999 copyright : (C) 1999 by Eric Espie email : torcs@free.fr version : $Id: gui.cpp,v 1.7 2006/10/06 14:13:55 berniw Exp $ ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /** @file This API is used to manage all the menu screens. @author Eric Espie @version $Id: gui.cpp,v 1.7 2006/10/06 14:13:55 berniw Exp $ @ingroup gui */ #include #include #include #include #include #include "gui.h" #include tGfuiScreen *GfuiScreen; /* current screen */ static int GfuiMouseVisible = 1; tMouseInfo GfuiMouse; int GfuiMouseHW = 0; float GfuiColor[GFUI_COLORNB][4]; static char buf[1024]; static int ScrW, ScrH, ViewW, ViewH; static tdble DelayRepeat; static double LastTimeClick; #define REPEAT1 1.0 #define REPEAT2 0.2 static void gfuiColorInit(void) { void *hdle; int i, j; char *rgba[4] = {GFSCR_ATTR_RED, GFSCR_ATTR_GREEN, GFSCR_ATTR_BLUE, GFSCR_ATTR_ALPHA}; char *clr[GFUI_COLORNB] = { GFSCR_ELT_BGCOLOR, GFSCR_ELT_TITLECOLOR, GFSCR_ELT_BGBTNFOCUS, GFSCR_ELT_BGBTNCLICK, GFSCR_ELT_BGBTNENABLED, GFSCR_ELT_BGBTNDISABLED, GFSCR_ELT_BTNFOCUS, GFSCR_ELT_BTNCLICK, GFSCR_ELT_BTNENABLED, GFSCR_ELT_BTNDISABLED, GFSCR_ELT_LABELCOLOR, GFSCR_ELT_TIPCOLOR, GFSCR_ELT_MOUSECOLOR1, GFSCR_ELT_MOUSECOLOR2, GFSCR_ELT_HELPCOLOR1, GFSCR_ELT_HELPCOLOR2, GFSCR_ELT_BGSCROLLIST, GFSCR_ELT_SCROLLIST, GFSCR_ELT_BGSELSCROLLIST, GFSCR_ELT_SELSCROLLIST, GFSCR_ELT_EDITCURSORCLR }; sprintf(buf, "%s%s", GetLocalDir(), GFSCR_CONF_FILE); hdle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT); for (i = 0; i < GFUI_COLORNB; i++) { for (j = 0; j < 4; j++) { sprintf(buf, "%s/%s/%s", GFSCR_SECT_MENUCOL, GFSCR_LIST_COLORS, clr[i]); GfuiColor[i][j] = GfParmGetNum(hdle, buf, rgba[j], (char*)NULL, 1.0); } } GfParmReleaseHandle(hdle); /* Remove the X11/Windows cursor */ if (!GfuiMouseHW) { glutSetCursor(GLUT_CURSOR_NONE); } GfuiMouseVisible = 1; } void gfuiInit(void) { gfuiButtonInit(); gfuiHelpInit(); gfuiLabelInit(); gfuiObjectInit(); gfuiColorInit(); gfuiLoadFonts(); /* glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF); */ } /** Dummy display function for glut. Declare this function to glut if nothing is to be displayed by the redisplay mechanism. @ingroup gui */ void GfuiDisplayNothing(void) { } /** Idle function for the GUI to be called during Idle loop of glut. @ingroup gui */ void GfuiIdle(void) { double curtime = GfTimeClock(); if ((curtime - LastTimeClick) > DelayRepeat) { DelayRepeat = REPEAT2; LastTimeClick = curtime; if (GfuiScreen->mouse == 1) { /* button down */ gfuiUpdateFocus(); gfuiMouseAction((void*)0); glutPostRedisplay(); } } } /** Display function for the GUI to be called during redisplay of glut. @ingroup gui */ void GfuiDisplay(void) { tGfuiObject *curObj; glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glDisable(GL_CULL_FACE); glDisable(GL_ALPHA_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GfScrGetSize(&ScrW, &ScrH, &ViewW, &ViewH); glViewport((ScrW-ViewW) / 2, (ScrH-ViewH) / 2, ViewW, ViewH); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, GfuiScreen->width, 0, GfuiScreen->height); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (GfuiScreen->bgColor[3] != 0.0) { glClearColor(GfuiScreen->bgColor[0], GfuiScreen->bgColor[1], GfuiScreen->bgColor[2], GfuiScreen->bgColor[3]); glClear(GL_COLOR_BUFFER_BIT); } if (GfuiScreen->bgImage != 0) { glDisable(GL_BLEND); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor3f(0.0, 0.0, 1.0); glBindTexture(GL_TEXTURE_2D, GfuiScreen->bgImage); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(0.0, GfuiScreen->height, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(GfuiScreen->width, GfuiScreen->height, 0.0); glTexCoord2f(1.0, 0.0); glVertex3f(GfuiScreen->width, 0.0, 0.0); glEnd(); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); } curObj = GfuiScreen->objects; if (curObj) { do { curObj = curObj->next; GfuiDraw(curObj); } while (curObj != GfuiScreen->objects); } if (!GfuiMouseHW && GfuiMouseVisible && GfuiScreen->mouseAllowed) { GfuiDrawCursor(); } glDisable(GL_BLEND); glutSwapBuffers(); } /** Hide the mouse cursor @ingroup gui @return none */ void GfuiMouseHide(void) { GfuiScreen->mouseAllowed = 0; } /** Show the mouse cursor @ingroup gui @return none */ void GfuiMouseShow(void) { GfuiScreen->mouseAllowed = 1; } /** Force the hardware mouse pointer @ingroup ctrl @return 0 ... Ok
-1 .. Error */ void GfuiMouseSetHWPresent(void) { GfuiMouseHW = 1; } static void gfuiKeyboard(unsigned char key, int /* x */, int /* y */) { tGfuiKey *curKey; int modifier; tGfuiObject *obj; modifier = glutGetModifiers(); /* user preempt key */ if (GfuiScreen->onKeyAction && GfuiScreen->onKeyAction(key, modifier, GFUI_KEY_DOWN)) { return; } /* now see the user's defined keys */ if (GfuiScreen->userKeys != NULL) { curKey = GfuiScreen->userKeys; do { curKey = curKey->next; if ((curKey->key == key) && ((curKey->modifier == 0) || (curKey->modifier & modifier) != 0)) { if (curKey->onPress) curKey->onPress(curKey->userData); break; } } while (curKey != GfuiScreen->userKeys); } obj = GfuiScreen->hasFocus; if (obj != NULL) { switch (obj->widget) { case GFUI_EDITBOX: gfuiEditboxKey(obj, (int)key, modifier); break; } } glutPostRedisplay(); } static void gfuiSpecial(int key, int /* x */, int /* y */) { tGfuiKey *curKey; int modifier; tGfuiObject *obj; modifier = glutGetModifiers(); /* user preempt key */ if (GfuiScreen->onSKeyAction && GfuiScreen->onSKeyAction(key, modifier, GFUI_KEY_DOWN)) { return; } /* now see the user's defined keys */ if (GfuiScreen->userSpecKeys != NULL) { curKey = GfuiScreen->userSpecKeys; do { curKey = curKey->next; if ((curKey->specialkey == key) && ((curKey->modifier == 0) || (curKey->modifier & modifier) != 0)) { if (curKey->onPress) curKey->onPress(curKey->userData); break; } } while (curKey != GfuiScreen->userSpecKeys); } obj = GfuiScreen->hasFocus; if (obj != NULL) { switch (obj->widget) { case GFUI_EDITBOX: gfuiEditboxKey(obj, key + 256, modifier); break; } } glutPostRedisplay(); } static void gfuiKeyboardUp(unsigned char key, int /* x */, int /* y */) { tGfuiKey *curKey; int modifier; modifier = glutGetModifiers(); /* user preempt key */ if (GfuiScreen->onKeyAction && GfuiScreen->onKeyAction(key, modifier, GFUI_KEY_UP)) { return; } /* now see the user's defined keys */ if (GfuiScreen->userKeys != NULL) { curKey = GfuiScreen->userKeys; do { curKey = curKey->next; if ((curKey->key == key) && ((curKey->modifier == 0) || (curKey->modifier & modifier) != 0)) { if (curKey->onRelease) curKey->onRelease(curKey->userData); break; } } while (curKey != GfuiScreen->userKeys); } glutPostRedisplay(); } static void gfuiSpecialUp(int key, int /* x */, int /* y */) { tGfuiKey *curKey; int modifier; modifier = glutGetModifiers(); /* user preempt key */ if (GfuiScreen->onSKeyAction && GfuiScreen->onSKeyAction(key, modifier, GFUI_KEY_UP)) { return; } /* now see the user's defined keys */ if (GfuiScreen->userSpecKeys != NULL) { curKey = GfuiScreen->userSpecKeys; do { curKey = curKey->next; if ((curKey->specialkey == key) && ((curKey->modifier == 0) || (curKey->modifier & modifier) != 0)) { if (curKey->onRelease) curKey->onRelease(curKey->userData); break; } } while (curKey != GfuiScreen->userSpecKeys); } glutPostRedisplay(); } /** Get the mouse information (position and buttons) @ingroup gui @return mouse information */ tMouseInfo *GfuiMouseInfo(void) { return &GfuiMouse; } /** Set the mouse position @ingroup gui @param x mouse x pos @param y mouse y pos @return none */ void GfuiMouseSetPos(int x, int y) { glutWarpPointer(x, y); } static void gfuiMouse(int button, int state, int x, int y) { // Check array range of button array! if (button > -1 && button < 3) { GfuiMouse.X = (x - (ScrW - ViewW)/2) * (int)GfuiScreen->width / ViewW; GfuiMouse.Y = (ViewH - y + (ScrH - ViewH)/2) * (int)GfuiScreen->height / ViewH; GfuiMouse.button[button] = 1 - state; DelayRepeat = REPEAT1; LastTimeClick = GfTimeClock(); if (state == GLUT_DOWN) { if (button == GLUT_RIGHT_BUTTON) { GfuiScreen->mouse = 0; /* GfuiMouseVisible = 1 - GfuiMouseVisible; */ gfuiUpdateFocus(); } else { GfuiScreen->mouse = 1; gfuiUpdateFocus(); gfuiMouseAction((void*)0); } } else { GfuiScreen->mouse = 0; gfuiUpdateFocus(); if (button != GLUT_RIGHT_BUTTON) { gfuiMouseAction((void*)1); } } glutPostRedisplay(); } } static void gfuiMotion(int x, int y) { GfuiMouse.X = (x - (ScrW - ViewW)/2) * (int)GfuiScreen->width / ViewW; GfuiMouse.Y = (ViewH - y + (ScrH - ViewH)/2) * (int)GfuiScreen->height / ViewH; gfuiUpdateFocus(); gfuiMouseAction((void*)(1 - GfuiScreen->mouse)); glutPostRedisplay(); DelayRepeat = REPEAT1; } static void gfuiPassiveMotion(int x, int y) { GfuiMouse.X = (x - (ScrW - ViewW)/2) * (int)GfuiScreen->width / ViewW; GfuiMouse.Y = (ViewH - y + (ScrH - ViewH)/2) * (int)GfuiScreen->height / ViewH; gfuiUpdateFocus(); glutPostRedisplay(); } /** Tell if the screen is active or not. @ingroup gui @param screen Screen to activate @return 1 if active and 0 if not. */ int GfuiScreenIsActive(void *screen) { return (GfuiScreen == screen); } /** Activate a screen and make it current. @ingroup gui @param screen Screen to activate @warning The current screen at the call time is deactivated. */ void GfuiScreenActivate(void *screen) { if ((GfuiScreen) && (GfuiScreen->onDeactivate)) GfuiScreen->onDeactivate(GfuiScreen->userDeactData); GfuiScreen = (tGfuiScreen*)screen; glutKeyboardFunc(gfuiKeyboard); glutSpecialFunc(gfuiSpecial); glutKeyboardUpFunc(gfuiKeyboardUp); glutSpecialUpFunc(gfuiSpecialUp); glutMouseFunc(gfuiMouse); glutMotionFunc(gfuiMotion); glutPassiveMotionFunc(gfuiPassiveMotion); glutIdleFunc(GfuiIdle); if (GfuiScreen->onlyCallback == 0) { if (GfuiScreen->hasFocus == NULL) { gfuiSelectNext(NULL); } glutDisplayFunc(GfuiDisplay); } else { glutDisplayFunc(GfuiDisplayNothing); } if (GfuiScreen->onActivate) GfuiScreen->onActivate(GfuiScreen->userActData); if (GfuiScreen->onlyCallback == 0) { GfuiDisplay(); glutPostRedisplay(); } } /** Activate a screen and make it current plus release the current screen. @ingroup gui @param screen Screen to activate @warning The current screen at the call time is deactivated. */ void GfuiScreenReplace(void *screen) { tGfuiScreen *oldScreen = GfuiScreen; //GfuiScreenActivate(screen); if (oldScreen) { GfuiScreenRelease(oldScreen); } GfuiScreenActivate(screen); } /** Deactivate the current screen. @ingroup gui */ void GfuiScreenDeactivate(void) { if (GfuiScreen->onDeactivate) GfuiScreen->onDeactivate(GfuiScreen->userDeactData); GfuiScreen = (tGfuiScreen*)NULL; glutKeyboardFunc((void(*)(unsigned char,int,int))NULL); glutSpecialFunc((void(*)(int,int,int))NULL); glutKeyboardUpFunc((void(*)(unsigned char,int,int))NULL); glutSpecialUpFunc((void(*)(int,int,int))NULL); glutMouseFunc((void(*)(int,int,int,int))NULL); glutMotionFunc((void(*)(int,int))NULL); glutPassiveMotionFunc((void(*)(int,int))NULL); glutIdleFunc((void(*)(void))NULL); glutDisplayFunc(GfuiDisplayNothing); } /** Create a new screen. @ingroup gui @return New screen instance
NULL if Error */ void * GfuiScreenCreate(void) { tGfuiScreen *screen; screen = (tGfuiScreen*)calloc(1, sizeof(tGfuiScreen)); screen->width = 640.0; screen->height = 480.0; screen->bgColor = (float*)calloc(4, sizeof(float)); int i; for(i = 0; i < 4; i++) { screen->bgColor[i] = GfuiColor[GFUI_BGCOLOR][i]; } // screen->bgColor = &(GfuiColor[GFUI_BGCOLOR][0]); screen->mouseColor[0] = &(GfuiColor[GFUI_MOUSECOLOR1][0]); screen->mouseColor[1] = &(GfuiColor[GFUI_MOUSECOLOR2][0]); screen->mouseAllowed = 1; return (void*)screen; } /** Create a screen. @ingroup gui @param bgColor pointer on color array (RGBA) (if NULL default color is used) @param userDataOnActivate Parameter to the activate function @param onActivate Function called when the screen is activated @param userDataOnDeactivate Parameter to the deactivate function @param onDeactivate Function called when the screen is deactivated @param mouseAllowed Flag to tell if the mouse cursor can be displayed @return New screen instance
NULL if Error @bug Only black background work well */ void * GfuiScreenCreateEx(float *bgColor, void *userDataOnActivate, tfuiCallback onActivate, void *userDataOnDeactivate, tfuiCallback onDeactivate, int mouseAllowed) { int i; tGfuiScreen *screen; screen = (tGfuiScreen*)calloc(1, sizeof(tGfuiScreen)); screen->width = 640.0; screen->height = 480.0; screen->bgColor = (float*)calloc(4, sizeof(float)); for(i = 0; i < 4; i++) { if (bgColor != NULL) { screen->bgColor[i] = bgColor[i]; } else { screen->bgColor[i] = GfuiColor[GFUI_BGCOLOR][i]; } } /* if (bgColor != NULL) { screen->bgColor = (float*)calloc(4, sizeof(float)); for(i = 0; i < 4; i++) { screen->bgColor[i] = bgColor[i]; } } else { screen->bgColor = &(GfuiColor[GFUI_BGCOLOR][0]); }*/ screen->mouseColor[0] = &(GfuiColor[GFUI_MOUSECOLOR1][0]); screen->mouseColor[1] = &(GfuiColor[GFUI_MOUSECOLOR2][0]); screen->onActivate = onActivate; screen->userActData = userDataOnActivate; screen->onDeactivate = onDeactivate; screen->userDeactData = userDataOnDeactivate; screen->mouseAllowed = mouseAllowed; return (void*)screen; } /** Release the given screen. @ingroup gui @param scr Screen to release @warning If the screen was activated, it is deactivated. */ void GfuiScreenRelease(void *scr) { tGfuiObject *curObject; tGfuiObject *nextObject; tGfuiKey *curKey; tGfuiKey *nextKey; tGfuiScreen *screen = (tGfuiScreen*)scr; if (GfuiScreen == screen) { GfuiScreenDeactivate(); } if (screen->bgImage != 0) { glDeleteTextures(1, &screen->bgImage); } if (screen->bgColor != NULL) { free(screen->bgColor); screen->bgColor = NULL; } curObject = screen->objects; if (curObject != NULL) { do { nextObject = curObject->next; gfuiReleaseObject(curObject); curObject = nextObject; } while (curObject != screen->objects); } curKey = screen->userKeys; if (curKey != NULL) { do { nextKey = curKey->next; free(curKey->name); free(curKey->descr); free(curKey); curKey = nextKey; } while (curKey != screen->userKeys); } curKey = screen->userSpecKeys; if (curKey != NULL) { do { nextKey = curKey->next; free(curKey->name); free(curKey->descr); free(curKey); curKey = nextKey; } while (curKey != screen->userSpecKeys); } free(screen); } /** Create a callback hook. @ingroup gui @param userDataOnActivate Parameter to the activate function @param onActivate Function called when the screen is activated @return New hook instance
NULL if Error */ void * GfuiHookCreate(void *userDataOnActivate, tfuiCallback onActivate) { tGfuiScreen *screen; screen = (tGfuiScreen*)calloc(1, sizeof(tGfuiScreen)); screen->onActivate = onActivate; screen->userActData = userDataOnActivate; screen->onlyCallback = 1; return (void*)screen; } /** Release the given hook. @ingroup gui @param hook Hook to release */ void GfuiHookRelease(void *hook) { free(hook); } void GfuiKeyEventRegister(void *scr, tfuiKeyCallback onKeyAction) { tGfuiScreen *screen = (tGfuiScreen*)scr; screen->onKeyAction = onKeyAction; } void GfuiSKeyEventRegister(void *scr, tfuiSKeyCallback onSKeyAction) { tGfuiScreen *screen = (tGfuiScreen*)scr; screen->onSKeyAction = onSKeyAction; } void GfuiKeyEventRegisterCurrent(tfuiKeyCallback onKeyAction) { GfuiScreen->onKeyAction = onKeyAction; } void GfuiSKeyEventRegisterCurrent(tfuiSKeyCallback onSKeyAction) { GfuiScreen->onSKeyAction = onSKeyAction; } /** Add a Keyboard callback to a screen. @ingroup gui @param scr Screen @param key Key code (glut value) @param descr Description for help screen @param userData Parameter to the callback function @param onKeyPressed Callback function @param onKeyReleased Callback function */ void GfuiAddKey(void *scr, unsigned char key, char *descr, void *userData, tfuiCallback onKeyPressed, tfuiCallback onKeyReleased) { tGfuiKey *curKey; tGfuiScreen *screen = (tGfuiScreen*)scr; char buf[16]; curKey = (tGfuiKey*)calloc(1, sizeof(tGfuiKey)); curKey->key = key; curKey->userData = userData; curKey->onPress = onKeyPressed; if (descr == NULL) { curKey->descr = strdup(""); } else { curKey->descr = strdup(descr); } switch(key){ case 8: curKey->name = strdup("backspace"); break; case 9: curKey->name = strdup("tab"); break; case 13: curKey->name = strdup("enter"); break; case 27: curKey->name = strdup("esc"); break; case ' ': curKey->name = strdup("space"); break; default: sprintf(buf, "%c", key); curKey->name = strdup(buf); break; } if (screen->userKeys == NULL) { screen->userKeys = curKey; curKey->next = curKey; } else { curKey->next = screen->userKeys->next; screen->userKeys->next = curKey; } } /** Add a Keyboard callback to the current screen. @ingroup gui @param key Key code (glut value) @param descr Description for help screen @param userData Parameter to the callback function @param onKeyPressed Callback function called when the specified key is pressed @param onKeyReleased Callback function */ void GfuiRegisterKey(unsigned char key, char *descr, void *userData, tfuiCallback onKeyPressed, tfuiCallback onKeyReleased) { GfuiAddKey(GfuiScreen, key, descr, userData, onKeyPressed, onKeyReleased); } /** Add a Special Keyboard shortcut to the screen. (see glut for normal and special keys) @ingroup gui @param scr Screen @param key Key code (glut value) @param descr Description for help screen @param userData Parameter to the callback function @param onKeyPressed Callback function @param onKeyReleased Callback function */ void GfuiAddSKey(void *scr, int key, char *descr, void *userData, tfuiCallback onKeyPressed, tfuiCallback onKeyReleased) { tGfuiKey *curKey; tGfuiScreen *screen = (tGfuiScreen*)scr; curKey = (tGfuiKey*)calloc(1, sizeof(tGfuiKey)); curKey->specialkey = key; curKey->userData = userData; curKey->onPress = onKeyPressed; if (descr == NULL) { curKey->descr = strdup(""); } else { curKey->descr = strdup(descr); } switch(key) { case GLUT_KEY_F1: curKey->name = strdup("F1"); break; case GLUT_KEY_F2: curKey->name = strdup("F2"); break; case GLUT_KEY_F3: curKey->name = strdup("F3"); break; case GLUT_KEY_F4: curKey->name = strdup("F4"); break; case GLUT_KEY_F5: curKey->name = strdup("F5"); break; case GLUT_KEY_F6: curKey->name = strdup("F6"); break; case GLUT_KEY_F7: curKey->name = strdup("F7"); break; case GLUT_KEY_F8: curKey->name = strdup("F8"); break; case GLUT_KEY_F9: curKey->name = strdup("F9"); break; case GLUT_KEY_F10: curKey->name = strdup("F10"); break; case GLUT_KEY_F11: curKey->name = strdup("F11"); break; case GLUT_KEY_F12: curKey->name = strdup("F12"); break; case GLUT_KEY_LEFT: curKey->name = strdup("Left Arrow"); break; case GLUT_KEY_UP: curKey->name = strdup("Up Arrow"); break; case GLUT_KEY_RIGHT: curKey->name = strdup("Right Arrow"); break; case GLUT_KEY_DOWN: curKey->name = strdup("Down Arrow"); break; case GLUT_KEY_PAGE_UP: curKey->name = strdup("Page Up"); break; case GLUT_KEY_PAGE_DOWN: curKey->name = strdup("Page Down"); break; case GLUT_KEY_HOME: curKey->name = strdup("Home"); break; case GLUT_KEY_END: curKey->name = strdup("End"); break; case GLUT_KEY_INSERT: curKey->name = strdup("Insert"); break; } if (screen->userSpecKeys == NULL) { screen->userSpecKeys = curKey; curKey->next = curKey; } else { curKey->next = screen->userSpecKeys->next; screen->userSpecKeys->next = curKey; screen->userSpecKeys = curKey; } } /** Save a screen shot in png format. @ingroup screen */ void GfuiScreenShot(void * /* notused */) { unsigned char *img; char buf[1024]; struct tm *stm; time_t t; int sw, sh, vw, vh; char path[1024]; snprintf(path, 1024, "%sscreenshots", GetLocalDir()); // Ensure that screenshot directory exists. if (GfCreateDir(path) == GF_DIR_CREATED) { GfScrGetSize(&sw, &sh, &vw, &vh); img = (unsigned char*)malloc(vw * vh * 3); if (img == NULL) { return; } glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadBuffer(GL_FRONT); glReadPixels((sw-vw)/2, (sh-vh)/2, vw, vh, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)img); t = time(NULL); stm = localtime(&t); snprintf(buf, 1024, "%s/torcs-%4d%02d%02d%02d%02d%02d.png", path, stm->tm_year+1900, stm->tm_mon+1, stm->tm_mday, stm->tm_hour, stm->tm_min, stm->tm_sec); GfImgWritePng(img, buf, vw, vh); free(img); } } /** Add an image background to a screen. @ingroup gui @param scr Screen @param filename file name of the bg image @return None. */ void GfuiScreenAddBgImg(void *scr, char *filename) { tGfuiScreen *screen = (tGfuiScreen*)scr; void *handle; float screen_gamma; GLbyte *tex; int w,h; if (screen->bgImage != 0) { glDeleteTextures(1, &screen->bgImage); } sprintf(buf, "%s%s", GetLocalDir(), GFSCR_CONF_FILE); handle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT); screen_gamma = (float)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_GAMMA, (char*)NULL, 2.0); tex = (GLbyte*)GfImgReadPng(filename, &w, &h, screen_gamma); if (!tex) { GfParmReleaseHandle(handle); return; } glGenTextures(1, &screen->bgImage); glBindTexture(GL_TEXTURE_2D, screen->bgImage); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)(tex)); free(tex); GfParmReleaseHandle(handle); }