]> git.jsancho.org Git - lugaru.git/blobdiff - Source/OpenGL_Windows.cpp
Moved image loading/saving in TGALoader and renamed it accordingly
[lugaru.git] / Source / OpenGL_Windows.cpp
index 2f92938789c3df346b2195183bbbf06eac6f6c80..475cd99bf1632e6a85f0a5f752b1cf8d691bf384 100644 (file)
@@ -3,57 +3,29 @@ Copyright (C) 2003, 2010 - Wolfire Games
 
 This file is part of Lugaru.
 
-Lugaru 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.
+Lugaru 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.
 
-This program is distributed in the hope that it will be useful,
+Lugaru is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 
 #ifdef WIN32
-#define UINT8 WIN32API_UINT8
-#define UINT16 WIN32API_UINT16
-#define boolean WIN32API_boolean
 #include <windows.h>
-#undef UINT8
-#undef UINT16
-#undef boolean
 #endif
 
-
-
 #include "Game.h"
-extern "C" {
-#include "zlib.h"
-#include "png.h"
-#ifdef WIN32
-#define INT32 INT32_jpeg
-#include "jpeglib.h"
-#undef INT32
-#else
-#include "jpeglib.h"
-#endif
-}
 
 using namespace Game;
 
-static bool load_image(const char * fname, TGAImageRec & tex);
-static bool load_png(const char * fname, TGAImageRec & tex);
-static bool load_jpg(const char * fname, TGAImageRec & tex);
-bool save_image(const char * fname);
-static bool save_png(const char * fname);
-
-
 #include "openal_wrapper.h"
 
 extern float multiplier;
@@ -72,6 +44,7 @@ bool gameFocused;
 
 extern float slomospeed;
 extern float slomofreq;
+extern bool visibleloading;
 
 
 
@@ -80,6 +53,8 @@ extern float slomofreq;
 #include <string.h>
 #include <fstream>
 #include <iostream>
+#include <zlib.h>
+#include <set>
 #include "gamegl.h"
 #include "MacCompatibility.h"
 #include "Settings.h"
@@ -89,18 +64,11 @@ extern float slomofreq;
 #include "win-res/resource.h"
 #endif
 
+extern SDL_Window *sdlwindow;
+
 using namespace std;
 
-SDL_Rect **resolutions = NULL;
-static SDL_Rect rect_1024_768 = { 0, 0, 1024, 768 };
-static SDL_Rect rect_800_600  = { 0, 0, 800,  600 };
-static SDL_Rect rect_640_480  = { 0, 0, 640,  480 };
-static SDL_Rect *hardcoded_resolutions[] = {
-    &rect_1024_768,
-    &rect_800_600,
-    &rect_640_480,
-    NULL
-};
+set<pair<int,int>> resolutions;
 
 Boolean SetUp ();
 void DoUpdate ();
@@ -114,6 +82,7 @@ void CleanUp (void);
 #pragma warning(disable: 4273)
 #endif
 
+#ifndef __MINGW32__ // FIXME: Temporary workaround for GL-8
 #define GL_FUNC(ret,fn,params,call,rt) \
     extern "C" { \
         static ret (GLAPIENTRY *p##fn) params = NULL; \
@@ -121,6 +90,7 @@ void CleanUp (void);
     }
 #include "glstubs.h"
 #undef GL_FUNC
+#endif // __MINGW32__
 
 #ifdef _MSC_VER
 #pragma warning(pop)
@@ -139,17 +109,21 @@ static bool lookup_glsym(const char *funcname, void **func)
 static bool lookup_all_glsyms(void)
 {
     bool retval = true;
+#ifndef __MINGW32__ // FIXME: Temporary workaround for GL-8
 #define GL_FUNC(ret,fn,params,call,rt) \
         if (!lookup_glsym(#fn, (void **) &p##fn)) retval = false;
 #include "glstubs.h"
 #undef GL_FUNC
+#endif // __MINGW32__
     return retval;
 }
 
+#ifndef __MINGW32__ // FIXME: Temporary workaround for GL-8
 static void GLAPIENTRY glDeleteTextures_doNothing(GLsizei n, const GLuint *textures)
 {
     // no-op.
 }
+#endif // __MINGW32__
 
 #ifdef MessageBox
 #undef MessageBox
@@ -163,10 +137,8 @@ int kContextHeight;
 
 Boolean gDone = false;
 
-#ifndef __MINGW32__
 static int _argc = 0;
 static char **_argv = NULL;
-#endif
 
 bool cmdline(const char *cmd)
 {
@@ -194,7 +166,6 @@ void initGL()
     glDisable( GL_ALPHA_TEST);
     glDisable( GL_BLEND);
     glDisable( GL_DEPTH_TEST);
-    //glDisable( GL_DITHER);
     glDisable( GL_FOG);
     glDisable( GL_LIGHTING);
     glDisable( GL_LOGIC_OP);
@@ -215,13 +186,11 @@ void initGL()
     glClearDepth( 1.0f);
     glDepthFunc( GL_LEQUAL);
     glDepthMask( GL_TRUE);
-    //glDepthRange( FRONT_CLIP, BACK_CLIP);
     glEnable( GL_DEPTH_TEST);
     glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
     glCullFace( GL_FRONT);
     glEnable( GL_CULL_FACE);
     glEnable( GL_LIGHTING);
-    //glEnable( GL_LIGHT_MODEL_AMBIENT);
     glEnable( GL_DITHER);
     glEnable( GL_COLOR_MATERIAL);
     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -236,47 +205,49 @@ void initGL()
     }
 }
 
-static void toggleFullscreen()
+void toggleFullscreen()
 {
-    if (!SDL_WM_ToggleFullScreen(SDL_GetVideoSurface())) {
-        SDL_Surface* screen = SDL_GetVideoSurface();
-        Uint32 flags = screen->flags;
-        screen = SDL_SetVideoMode(0, 0, 0, flags ^ SDL_FULLSCREEN);
-        if (!screen)
-            screen = SDL_SetVideoMode(0, 0, 0, flags);
-        if (!screen)
-            exit(1);
-        //reload opengl state
-        initGL();
-        Texture::reloadAll();
-        if (text)
-            text->BuildFont();
-        if (firstload) {
-            screentexture = 0;
-            LoadScreenTexture();
-        }
-        screentexture2 = 0;
+    fullscreen = !fullscreen;
+    Uint32 flags = SDL_GetWindowFlags(sdlwindow);
+    if (flags & SDL_WINDOW_FULLSCREEN) {
+        flags &= ~SDL_WINDOW_FULLSCREEN;
+    } else {
+        flags |= SDL_WINDOW_FULLSCREEN;
     }
+    SDL_SetWindowFullscreen(sdlwindow, flags);
 }
 
-static void sdlEventProc(const SDL_Event &e)
+static SDL_bool sdlEventProc(const SDL_Event &e)
 {
     switch (e.type) {
-    case SDL_MOUSEMOTION:
-        deltah += e.motion.xrel;
-        deltav += e.motion.yrel;
+        case SDL_QUIT:
+            return SDL_FALSE;
+
+        case SDL_WINDOWEVENT:
+            if (e.window.event == SDL_WINDOWEVENT_CLOSE) {
+                return SDL_FALSE;
+            }
         break;
 
-    case SDL_KEYDOWN:
-        if ((e.key.keysym.sym == SDLK_g) &&
-                (e.key.keysym.mod & KMOD_CTRL) &&
-                !(SDL_GetVideoSurface()->flags & SDL_FULLSCREEN) ) {
-            SDL_WM_GrabInput( ((SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON) ? SDL_GRAB_OFF : SDL_GRAB_ON) );
-        } else if ( (e.key.keysym.sym == SDLK_RETURN) && (e.key.keysym.mod & KMOD_ALT) ) {
-            toggleFullscreen();
-        }
+        case SDL_MOUSEMOTION:
+            deltah += e.motion.xrel;
+            deltav += e.motion.yrel;
+        break;
+
+        case SDL_KEYDOWN:
+            if ((e.key.keysym.scancode == SDL_SCANCODE_G) &&
+                (e.key.keysym.mod & KMOD_CTRL)) {
+                SDL_bool mode = SDL_TRUE;
+                if ((SDL_GetWindowFlags(sdlwindow) & SDL_WINDOW_FULLSCREEN) == 0)
+                    mode = (SDL_GetWindowGrab(sdlwindow) ? SDL_FALSE : SDL_TRUE);
+                SDL_SetWindowGrab(sdlwindow, mode);
+                SDL_SetRelativeMouseMode(mode);
+            } else if ( (e.key.keysym.scancode == SDL_SCANCODE_RETURN) && (e.key.keysym.mod & KMOD_ALT) ) {
+                toggleFullscreen();
+            }
         break;
     }
+    return SDL_TRUE;
 }
 
 
@@ -287,8 +258,6 @@ static Point gMidPoint;
 
 Boolean SetUp ()
 {
-    char string[10];
-
     LOGFUNC;
 
     osx = 0;
@@ -318,84 +287,97 @@ Boolean SetUp ()
         return false;
     }
 
-    SDL_Rect **res = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_OPENGL);
-    if ( (res == NULL) || (res == ((SDL_Rect **) - 1)) || (res[0] == NULL) || (res[0]->w < 640) || (res[0]->h < 480) )
-        res = hardcoded_resolutions;
-
-    // reverse list (it was sorted biggest to smallest by SDL)...
-    int count;
-    for (count = 0; res[count]; count++) {
-        if ((res[count]->w < 640) || (res[count]->h < 480))
-            break;   // sane lower limit.
+    for (int displayIdx = 0; displayIdx < SDL_GetNumVideoDisplays(); ++displayIdx) {
+        for (int i = 0; i < SDL_GetNumDisplayModes(displayIdx); ++i) {
+            SDL_DisplayMode mode;
+            if (SDL_GetDisplayMode(displayIdx, i, &mode) == -1)
+                continue;
+            if ((mode.w < 640) || (mode.h < 480))
+                continue;  // sane lower limit.
+            pair<int,int> resolution(mode.w, mode.h);
+            resolutions.insert(resolution);
+        }
     }
 
-    static SDL_Rect *resolutions_block = NULL;
-    resolutions_block = (SDL_Rect*) realloc(resolutions_block, sizeof (SDL_Rect) * count);
-    resolutions = (SDL_Rect**) realloc(resolutions, sizeof (SDL_Rect *) * (count + 1));
-    if ((resolutions_block == NULL) || (resolutions == NULL)) {
+    if (resolutions.empty()) {
+        const std::string error = "No suitable video resolutions found.";
+        cerr << error << endl;
+        SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Lugaru init failed!", error.c_str(), NULL);
         SDL_Quit();
-        fprintf(stderr, "Out of memory!\n");
         return false;
     }
 
-    resolutions[count--] = NULL;
-    for (int i = 0; count >= 0; i++, count--) {
-        memcpy(&resolutions_block[count], res[i], sizeof (SDL_Rect));
-        resolutions[count] = &resolutions_block[count];
-    }
-
     if (cmdline("showresolutions")) {
-        printf("Resolutions we think are okay:\n");
-        for (int i = 0; resolutions[i]; i++)
-            printf("  %d x %d\n", (int) resolutions[i]->w, (int) resolutions[i]->h);
+        printf("Available resolutions:\n");
+        for (auto resolution = resolutions.begin(); resolution != resolutions.end(); resolution++) {
+            printf("  %d x %d\n", (int) resolution->first, (int) resolution->second);
+        }
     }
 
-    Uint32 sdlflags = SDL_OPENGL;
-
-    if (!cmdline("windowed"))
-        sdlflags |= SDL_FULLSCREEN;
-
-    SDL_WM_SetCaption("Lugaru", "Lugaru");
-
-    SDL_ShowCursor(0);
-
     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
     SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1);
-#if SDL_VERSION_ATLEAST(1, 2, 10)
-    SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, vblsync);
-#endif
 
-    if (SDL_SetVideoMode(kContextWidth, kContextHeight, 0, sdlflags) == NULL) {
-        fprintf(stderr, "SDL_SetVideoMode() failed: %s\n", SDL_GetError());
+    Uint32 sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
+    if ((fullscreen || cmdline("fullscreen")) && !cmdline("windowed")) {
+        fullscreen = 1;
+        sdlflags |= SDL_WINDOW_FULLSCREEN;
+    }
+    if (!cmdline("nomousegrab"))
+        sdlflags |= SDL_WINDOW_INPUT_GRABBED;
+
+    sdlwindow = SDL_CreateWindow("Lugaru", SDL_WINDOWPOS_CENTERED_DISPLAY(0), SDL_WINDOWPOS_CENTERED_DISPLAY(0),
+                                 kContextWidth, kContextHeight, sdlflags);
+
+    if (!sdlwindow) {
+        fprintf(stderr, "SDL_CreateWindow() failed: %s\n", SDL_GetError());
         fprintf(stderr, "forcing 640x480...\n");
         kContextWidth = 640;
         kContextHeight = 480;
-        if (SDL_SetVideoMode(kContextWidth, kContextHeight, 0, sdlflags) == NULL) {
-            fprintf(stderr, "SDL_SetVideoMode() failed: %s\n", SDL_GetError());
+        sdlwindow = SDL_CreateWindow("Lugaru", SDL_WINDOWPOS_CENTERED_DISPLAY(0), SDL_WINDOWPOS_CENTERED_DISPLAY(0),
+                                     kContextWidth, kContextHeight, sdlflags);
+        if (!sdlwindow) {
+            fprintf(stderr, "SDL_CreateWindow() failed: %s\n", SDL_GetError());
             fprintf(stderr, "forcing 640x480 windowed mode...\n");
-            sdlflags &= ~SDL_FULLSCREEN;
-            if (SDL_SetVideoMode(kContextWidth, kContextHeight, 0, sdlflags) == NULL) {
-                fprintf(stderr, "SDL_SetVideoMode() failed: %s\n", SDL_GetError());
+            sdlflags &= ~SDL_WINDOW_FULLSCREEN;
+            sdlwindow = SDL_CreateWindow("Lugaru", SDL_WINDOWPOS_CENTERED_DISPLAY(0), SDL_WINDOWPOS_CENTERED_DISPLAY(0),
+                                         kContextWidth, kContextHeight, sdlflags);
+
+            if (!sdlwindow) {
+                fprintf(stderr, "SDL_CreateWindow() failed: %s\n", SDL_GetError());
                 return false;
             }
         }
     }
 
-    int dblbuf = 0;
-    if ((SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &dblbuf) == -1) || (!dblbuf)) {
-        fprintf(stderr, "Failed to get double buffered GL context!\n");
+    SDL_GLContext glctx = SDL_GL_CreateContext(sdlwindow);
+    if (!glctx) {
+        fprintf(stderr, "SDL_GL_CreateContext() failed: %s\n", SDL_GetError());
         SDL_Quit();
         return false;
     }
 
+    SDL_GL_MakeCurrent(sdlwindow, glctx);
+
     if (!lookup_all_glsyms()) {
+        fprintf(stderr, "Missing required OpenGL functions.\n");
         SDL_Quit();
         return false;
     }
 
-    if (!cmdline("nomousegrab"))
-        SDL_WM_GrabInput(SDL_GRAB_ON);
+    int dblbuf = 0;
+    if ((SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &dblbuf) == -1) || (!dblbuf))
+    {
+        fprintf(stderr, "Failed to get a double-buffered context.\n");
+        SDL_Quit();
+        return false;
+    }
 
+    if (SDL_GL_SetSwapInterval(-1) == -1)  // try swap_tear first.
+        SDL_GL_SetSwapInterval(1);
+
+    SDL_ShowCursor(0);
+    if (!cmdline("nomousegrab"))
+        SDL_SetRelativeMouseMode(SDL_TRUE);
 
     initGL();
 
@@ -410,6 +392,12 @@ Boolean SetUp ()
     newscreenwidth = screenwidth;
     newscreenheight = screenheight;
 
+    /* If saved resolution is not in the list, add it to the list (so that it’s selectable in the options) */
+    pair<int,int> startresolution(width,height);
+    if (resolutions.find(startresolution) == resolutions.end()) {
+        resolutions.insert(startresolution);
+    }
+
     InitGame();
 
     return true;
@@ -564,12 +552,14 @@ void CleanUp (void)
     LOGFUNC;
 
     SDL_Quit();
+#ifndef __MINGW32__ // FIXME: Temporary workaround for GL-8
 #define GL_FUNC(ret,fn,params,call,rt) p##fn = NULL;
 #include "glstubs.h"
 #undef GL_FUNC
     // cheat here...static destructors are calling glDeleteTexture() after
     //  the context is destroyed and libGL unloaded by SDL_Quit().
     pglDeleteTextures = glDeleteTextures_doNothing;
+#endif // __MINGW32__
 
 }
 
@@ -577,7 +567,7 @@ void CleanUp (void)
 
 static bool IsFocused()
 {
-    return ((SDL_GetAppState() & SDL_APPINPUTFOCUS) != 0);
+    return ((SDL_GetWindowFlags(sdlwindow) & SDL_WINDOW_INPUT_FOCUS) != 0);
 }
 
 
@@ -637,7 +627,6 @@ char *calcBaseDir(const char *argv0)
     char *retval;
     char *envr;
 
-    const char *ptr = strrchr((char *)argv0, '/');
     if (strchr(argv0, '/')) {
         retval = strdup(argv0);
         if (retval)
@@ -681,10 +670,8 @@ static inline void chdirToAppPath(const char *argv0)
 
 int main(int argc, char **argv)
 {
-#ifndef __MINGW32__
     _argc = argc;
     _argv = argv;
-#endif
 
     // !!! FIXME: we could use a Win32 API for this.  --ryan.
 #ifndef WIN32
@@ -717,11 +704,10 @@ int main(int argc, char **argv)
                     if (!waiting) {
                         // message pump
                         while ( SDL_PollEvent( &e ) ) {
-                            if ( e.type == SDL_QUIT ) {
+                            if (!sdlEventProc(e)) {
                                 gDone = true;
                                 break;
                             }
-                            sdlEventProc(e);
                         }
                     }
 
@@ -735,12 +721,7 @@ int main(int argc, char **argv)
                     }
 
                     // game is not in focus, give CPU time to other apps by waiting for messages instead of 'peeking'
-                    SDL_ActiveEvent evt;
-                    SDL_WaitEvent((SDL_Event*)&evt);
-                    if (evt.type == SDL_ACTIVEEVENT && evt.gain == 1)
-                        gameFocused = true;
-                    else if (evt.type == SDL_QUIT)
-                        gDone = true;
+                    SDL_WaitEvent(0);
                 }
             }
 
@@ -765,272 +746,3 @@ int main(int argc, char **argv)
 
     return -1;
 }
-
-
-
-// --------------------------------------------------------------------------
-
-
-bool LoadImage(const char * fname, TGAImageRec & tex)
-{
-    if ( tex.data == NULL )
-        return false;
-    else
-        return load_image(fname, tex);
-}
-
-void ScreenShot(const char * fname)
-{
-
-}
-
-
-
-static bool load_image(const char *file_name, TGAImageRec &tex)
-{
-    const char *ptr = strrchr((char *)file_name, '.');
-    if (ptr) {
-        if (strcasecmp(ptr + 1, "png") == 0)
-            return load_png(file_name, tex);
-        else if (strcasecmp(ptr + 1, "jpg") == 0)
-            return load_jpg(file_name, tex);
-    }
-
-    STUBBED("Unsupported image type");
-    return false;
-}
-
-
-struct my_error_mgr {
-    struct jpeg_error_mgr pub; /* "public" fields */
-    jmp_buf setjmp_buffer; /* for return to caller */
-};
-typedef struct my_error_mgr * my_error_ptr;
-
-
-static void my_error_exit(j_common_ptr cinfo)
-{
-    struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err;
-    longjmp(err->setjmp_buffer, 1);
-}
-
-/* stolen from public domain example.c code in libjpg distribution. */
-static bool load_jpg(const char *file_name, TGAImageRec &tex)
-{
-    struct jpeg_decompress_struct cinfo;
-    struct my_error_mgr jerr;
-    JSAMPROW buffer[1]; /* Output row buffer */
-    int row_stride; /* physical row width in output buffer */
-    FILE *infile = fopen(file_name, "rb");
-
-    if (infile == NULL)
-        return false;
-
-    cinfo.err = jpeg_std_error(&jerr.pub);
-    jerr.pub.error_exit = my_error_exit;
-    if (setjmp(jerr.setjmp_buffer)) {
-        jpeg_destroy_decompress(&cinfo);
-        fclose(infile);
-        return false;
-    }
-
-    jpeg_create_decompress(&cinfo);
-    jpeg_stdio_src(&cinfo, infile);
-    (void) jpeg_read_header(&cinfo, TRUE);
-
-    cinfo.out_color_space = JCS_RGB;
-    cinfo.quantize_colors = 0;
-    (void) jpeg_calc_output_dimensions(&cinfo);
-    (void) jpeg_start_decompress(&cinfo);
-
-    row_stride = cinfo.output_width * cinfo.output_components;
-    tex.sizeX = cinfo.output_width;
-    tex.sizeY = cinfo.output_height;
-    tex.bpp = 24;
-
-    while (cinfo.output_scanline < cinfo.output_height) {
-        buffer[0] = (JSAMPROW)(char *)tex.data +
-                    ((cinfo.output_height - 1) - cinfo.output_scanline) * row_stride;
-        (void) jpeg_read_scanlines(&cinfo, buffer, 1);
-    }
-
-    (void) jpeg_finish_decompress(&cinfo);
-    jpeg_destroy_decompress(&cinfo);
-    fclose(infile);
-
-    return true;
-}
-
-
-/* stolen from public domain example.c code in libpng distribution. */
-static bool load_png(const char *file_name, TGAImageRec &tex)
-{
-    bool hasalpha = false;
-    png_structp png_ptr = NULL;
-    png_infop info_ptr = NULL;
-    png_uint_32 width, height;
-    int bit_depth, color_type, interlace_type;
-    png_byte **rows = NULL;
-    bool retval = false;
-    png_byte **row_pointers = NULL;
-    FILE *fp = fopen(file_name, "rb");
-
-    if (fp == NULL) {
-        cerr << file_name << " not found" << endl;
-        return(NULL);
-    }
-
-    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (png_ptr == NULL)
-        goto png_done;
-
-    info_ptr = png_create_info_struct(png_ptr);
-    if (info_ptr == NULL)
-        goto png_done;
-
-    if (setjmp(png_jmpbuf(png_ptr)))
-        goto png_done;
-
-    png_init_io(png_ptr, fp);
-    png_read_png(png_ptr, info_ptr,
-                 PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING,
-                 NULL);
-    png_get_IHDR(png_ptr, info_ptr, &width, &height,
-                 &bit_depth, &color_type, &interlace_type, NULL, NULL);
-
-    if (bit_depth != 8)  // transform SHOULD handle this...
-        goto png_done;
-
-    if (color_type & PNG_COLOR_MASK_PALETTE)  // !!! FIXME?
-        goto png_done;
-
-    if ((color_type & PNG_COLOR_MASK_COLOR) == 0)  // !!! FIXME?
-        goto png_done;
-
-    hasalpha = ((color_type & PNG_COLOR_MASK_ALPHA) != 0);
-    row_pointers = png_get_rows(png_ptr, info_ptr);
-    if (!row_pointers)
-        goto png_done;
-
-    if (!hasalpha) {
-        png_byte *dst = tex.data;
-        for (int i = height - 1; i >= 0; i--) {
-            png_byte *src = row_pointers[i];
-            for (int j = 0; j < width; j++) {
-                dst[0] = src[0];
-                dst[1] = src[1];
-                dst[2] = src[2];
-                dst[3] = 0xFF;
-                src += 3;
-                dst += 4;
-            }
-        }
-    }
-
-    else {
-        png_byte *dst = tex.data;
-        int pitch = width * 4;
-        for (int i = height - 1; i >= 0; i--, dst += pitch)
-            memcpy(dst, row_pointers[i], pitch);
-    }
-
-    tex.sizeX = width;
-    tex.sizeY = height;
-    tex.bpp = 32;
-    retval = true;
-
-png_done:
-    if (!retval) {
-        cerr << "There was a problem loading " << file_name << endl;
-    }
-    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-    if (fp)
-        fclose(fp);
-    return (retval);
-}
-
-
-bool save_image(const char *file_name)
-{
-    const char *ptr = strrchr((char *)file_name, '.');
-    if (ptr) {
-        if (strcasecmp(ptr + 1, "png") == 0)
-            return save_png(file_name);
-    }
-
-    STUBBED("Unsupported image type");
-    return false;
-}
-
-
-static bool save_png(const char *file_name)
-{
-    FILE *fp = NULL;
-    png_structp png_ptr = NULL;
-    png_infop info_ptr = NULL;
-    bool retval = false;
-
-    fp = fopen(file_name, "wb");
-    if (fp == NULL)
-        return false;
-
-    png_bytep *row_pointers = new png_bytep[kContextHeight];
-    png_bytep screenshot = new png_byte[kContextWidth * kContextHeight * 3];
-    if ((!screenshot) || (!row_pointers))
-        goto save_png_done;
-
-    glGetError();
-    glReadPixels(0, 0, kContextWidth, kContextHeight,
-                 GL_RGB, GL_UNSIGNED_BYTE, screenshot);
-    if (glGetError() != GL_NO_ERROR)
-        goto save_png_done;
-
-    for (int i = 0; i < kContextHeight; i++)
-        row_pointers[i] = screenshot + ((kContextWidth * ((kContextHeight - 1) - i)) * 3);
-
-    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (png_ptr == NULL)
-        goto save_png_done;
-
-    info_ptr = png_create_info_struct(png_ptr);
-    if (info_ptr == NULL)
-        goto save_png_done;
-
-    if (setjmp(png_jmpbuf(png_ptr)))
-        goto save_png_done;
-
-    png_init_io(png_ptr, fp);
-
-    if (setjmp(png_jmpbuf(png_ptr)))
-        goto save_png_done;
-
-    png_set_IHDR(png_ptr, info_ptr, kContextWidth, kContextHeight,
-                 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
-                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
-    png_write_info(png_ptr, info_ptr);
-
-    if (setjmp(png_jmpbuf(png_ptr)))
-        goto save_png_done;
-
-    png_write_image(png_ptr, row_pointers);
-
-    if (setjmp(png_jmpbuf(png_ptr)))
-        goto save_png_done;
-
-    png_write_end(png_ptr, NULL);
-    retval = true;
-
-save_png_done:
-    png_destroy_write_struct(&png_ptr, &info_ptr);
-    delete[] screenshot;
-    delete[] row_pointers;
-    if (fp)
-        fclose(fp);
-    if (!retval)
-        unlink(ConvertFileName(file_name));
-    return retval;
-}
-
-
-