imagewin.cc

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 1998 Jeffrey S. Freedman
00009 
00010 This library is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU Library General Public
00012 License as published by the Free Software Foundation; either
00013 version 2 of the License, or (at your option) any later version.
00014 
00015 This library is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 Library General Public License for more details.
00019 
00020 You should have received a copy of the GNU Library General Public
00021 License along with this library; if not, write to the
00022 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00023 Boston, MA  02111-1307, USA.
00024 */
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #  include <config.h>
00028 #endif
00029 
00030 #include "imagewin.h"
00031 
00032 #ifndef ALPHA_LINUX_CXX
00033 #  include <cstring>
00034 #  include <cstdlib>
00035 #  include <iostream>
00036 #  include <string>
00037 #endif
00038 #include "exult_types.h"
00039 #include "utils.h"
00040 
00041 #include "SDL_video.h"
00042 #include "SDL_error.h"
00043 
00044 #ifdef HAVE_OPENGL
00045 #include <GL/gl.h>
00046 #endif
00047 
00048 bool SavePCX_RW (SDL_Surface *saveme, SDL_RWops *dst, bool freedst);
00049 
00050 #ifndef UNDER_CE
00051 using std::cout;
00052 using std::cerr;
00053 using std::endl;
00054 using std::exit;
00055 #endif
00056 
00057 // This is all the names of the scalers. It needs to match the ScalerType enum
00058 const char *Image_window::ScalerNames[] =  {
00059     "Point",
00060     "Interlaced",
00061     "Bilinear",
00062     "BilinearPlus",
00063     "2xSaI",
00064     "SuperEagle",
00065     "Super2xSaI",
00066     "Scale2X",
00067     "OpenGL",
00068     0
00069 };
00070 
00071 Image_window::ScalerType Image_window::get_scaler_for_name(const std::string &scaler)
00072 {
00073   std::string sclr = to_uppercase(scaler);
00074 
00075   for (int s = 0; s < NumScalers; s++) {
00076     std::string sclr2 = to_uppercase(ScalerNames[s]);
00077     if (sclr == sclr2) return (ScalerType) s;
00078   }
00079 
00080   return NoScaler;
00081 }
00082 
00083 /*
00084  *  Get best depth.  Returns bits/pixel.
00085  */
00086 static int Get_best_depth
00087   (
00088   )
00089   {
00090           // Get video info.
00091   const SDL_VideoInfo *vinfo = SDL_GetVideoInfo();
00092           // The "best" format:
00093   return (vinfo->vfmt->BitsPerPixel);
00094   }
00095 
00096 /*
00097  *  Destroy window.
00098  */
00099 
00100 Image_window::~Image_window
00101   (
00102   )
00103   {
00104   free_surface();
00105   delete ibuf;
00106   }
00107 
00108 /*
00109  *  Create the surface.
00110  */
00111 
00112 void Image_window::create_surface
00113   (
00114   unsigned int w, 
00115   unsigned int h
00116   )
00117   {
00118   ibuf->width = w;
00119   ibuf->height = h;
00120   Uint32 flags = (fullscreen?SDL_FULLSCREEN:0) |
00121           SDL_SWSURFACE |  SDL_HWPALETTE;
00122   uses_palette = true;
00123   show_scaled = 0;
00124   unscaled_surface = surface = scaled_surface = 0;
00125   
00126 #if defined(__zaurus__)
00127   flags &= ~SDL_FULLSCREEN; // Zaurus would crash in fullscreen mode
00128 #else
00129   if (try_scaler(w, h, flags)) return; // everyone else can test the try_scaler function
00130 #endif
00131 
00132   if (!surface)     // No scaling, or failed?
00133     {
00134     unscaled_surface = surface = SDL_SetVideoMode(w, h, ibuf->depth, flags);
00135     scale = 1;
00136     }
00137   if (!surface)
00138     {
00139     cout << "Couldn't set video mode (" << w << ", " << h <<
00140       ") at " << ibuf->depth << " bpp depth: " <<
00141       SDL_GetError() << endl;
00142     exit(-1);
00143     }
00144   ibuf->bits = (unsigned char *) surface->pixels;
00145           // Update line size in words.
00146   ibuf->line_width = surface->pitch/ibuf->pixel_size;
00147   }
00148 
00149 bool Image_window::try_scaler(int w, int h, uint32 flags)
00150 {
00151   // OpenGL
00152   if (scaler ==OpenGL)
00153     {
00154 #ifdef HAVE_OPENGL
00155           // Get info. about video.
00156     const SDL_VideoInfo *vinfo = SDL_GetVideoInfo();
00157     if (!vinfo)
00158       {
00159       cout << "SDL_GetVideoInfo() failed: " << SDL_GetError()
00160               << endl;
00161       return false;
00162       }
00163           // Set up SDL video flags.
00164     int video_flags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER |
00165         SDL_HWPALETTE | SDL_RESIZABLE |
00166         (flags&SDL_FULLSCREEN);
00167           // Can surface be in video RAM?
00168     if (vinfo->hw_available)
00169       video_flags |= SDL_HWSURFACE;
00170     else
00171       video_flags |= SDL_SWSURFACE;
00172     if (vinfo->blit_hw) // Hardware blits?
00173       video_flags |= SDL_HWACCEL;
00174           // Want double-buffering.
00175     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
00176           // Allocate surface.
00177     int hwdepth = vinfo->vfmt->BitsPerPixel;
00178           // +++++For now create 8-bit surface
00179           //   to avoid crashing places we
00180           //   haven't converted yet.
00181     if ((scaled_surface = SDL_SetVideoMode(scale*w, scale*h, 
00182             hwdepth, video_flags)) != 0 &&
00183         (unscaled_surface = surface = SDL_CreateRGBSurface(
00184           SDL_SWSURFACE, w, h,
00185             8, 0, 0, 0, 0)) != 0)
00186       {
00187       show_scaled = &Image_window::show_scaledOpenGL;
00188       }
00189     else
00190       {
00191       cerr << "Couldn't allocate surface: " << 
00192           SDL_GetError() << endl;
00193       delete surface;
00194       delete scaled_surface;
00195       surface = scaled_surface = 0;
00196       }
00197 #else
00198     cerr << "OpenGL not supported" << endl;
00199 #endif
00200     }
00201   // 2xSaI scaler
00202   else if (scale == 2 && scaler ==  SaI)
00203   {
00204     int hwdepth;
00205     
00206     if ( SDL_VideoModeOK(w, h, 32, flags))
00207       hwdepth = 32;
00208     else if ( SDL_VideoModeOK(w, h, 16, flags))
00209       hwdepth = 16;
00210     else
00211       hwdepth = Get_best_depth();
00212 
00213     if ((hwdepth != 16 && hwdepth != 32) || ibuf->depth != 8)
00214       cout << "Doubling from " << ibuf->depth << "bits to "
00215         << hwdepth << " not yet supported." << endl;
00216     else if ((scaled_surface = SDL_SetVideoMode(2*w, 2*h, 
00217             hwdepth, flags)) != 0 &&
00218        (unscaled_surface = surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
00219               8, 0, 0, 0, 0)) != 0)
00220     {     // Get color mask info.
00221       SDL_PixelFormat *fmt = scaled_surface->format;
00222       uint32 r = fmt->Rmask, g=fmt->Gmask, b=fmt->Bmask;
00223       if (hwdepth == 16)
00224       {
00225         show_scaled = (r == 0xf800 && g == 0x7e0 &&b == 0x1f) ? 
00226           &Image_window::show_scaled8to565_2xSaI
00227            : (r == 0x7c00 && g == 0x3e0 && b == 0x1f) ?
00228           &Image_window::show_scaled8to555_2xSaI
00229            : &Image_window::show_scaled8to16_2xSaI;
00230       }
00231       else
00232             show_scaled = &Image_window::show_scaled8to32_2xSaI;
00233 
00234       uses_palette = false;
00235     }
00236     else
00237     {
00238       cout << "Couldn't create scaled surface" << endl;
00239       delete surface;
00240       delete scaled_surface;
00241       surface = scaled_surface = 0;
00242     }
00243   }
00244   else if (scale == 2 && scaler == bilinear)  // Bilinear scaler
00245   {
00246     int hwdepth;
00247     
00248     if ( SDL_VideoModeOK(w, h, 32, flags))
00249       hwdepth = 32;
00250     else if ( SDL_VideoModeOK(w, h, 16, flags))
00251       hwdepth = 16;
00252     else
00253       hwdepth = Get_best_depth();
00254 
00255     if ((hwdepth != 16 && hwdepth != 32) || ibuf->depth != 8)
00256       cout << "Doubling from " << ibuf->depth << "bits to "
00257         << hwdepth << " not yet supported." << endl;
00258     else if ((scaled_surface = SDL_SetVideoMode(2*w, 2*h, 
00259             hwdepth, flags)) != 0 &&
00260        (unscaled_surface = surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
00261               8, 0, 0, 0, 0)) != 0)
00262     {     // Get color mask info.
00263       SDL_PixelFormat *fmt = scaled_surface->format;
00264       uint32 r = fmt->Rmask, g=fmt->Gmask, b=fmt->Bmask;
00265       if (hwdepth == 16)
00266       {
00267         show_scaled = (r == 0xf800 && g == 0x7e0 &&b == 0x1f) ? 
00268           &Image_window::show_scaled8to565_bilinear
00269            : (r == 0x7c00 && g == 0x3e0 && b == 0x1f) ?
00270           &Image_window::show_scaled8to555_bilinear
00271            : &Image_window::show_scaled8to16_bilinear;
00272       }
00273       else
00274             show_scaled = &Image_window::show_scaled8to32_bilinear;
00275 
00276       uses_palette = false;
00277     }
00278     else
00279     {
00280       cout << "Couldn't create scaled surface" << endl;
00281       delete surface;
00282       delete scaled_surface;
00283       surface = scaled_surface = 0;
00284     }
00285   }
00286   else if (scale == 2 && scaler == BilinearPlus)  // Bilinear Plus scaler
00287   {
00288     int hwdepth;
00289     
00290     if ( SDL_VideoModeOK(w, h, 32, flags))
00291       hwdepth = 32;
00292     else if ( SDL_VideoModeOK(w, h, 16, flags))
00293       hwdepth = 16;
00294     else
00295       hwdepth = Get_best_depth();
00296 
00297     if ((hwdepth != 16 && hwdepth != 32) || ibuf->depth != 8)
00298       cout << "Doubling from " << ibuf->depth << "bits to "
00299         << hwdepth << " not yet supported." << endl;
00300     else if ((scaled_surface = SDL_SetVideoMode(2*w, 2*h, 
00301             hwdepth, flags)) != 0 &&
00302        (unscaled_surface = surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
00303               8, 0, 0, 0, 0)) != 0)
00304     {     // Get color mask info.
00305       SDL_PixelFormat *fmt = scaled_surface->format;
00306       uint32 r = fmt->Rmask, g=fmt->Gmask, b=fmt->Bmask;
00307       if (hwdepth == 16)
00308       {
00309         show_scaled = (r == 0xf800 && g == 0x7e0 &&b == 0x1f) ? 
00310           &Image_window::show_scaled8to565_BilinearPlus
00311            : (r == 0x7c00 && g == 0x3e0 && b == 0x1f) ?
00312           &Image_window::show_scaled8to555_BilinearPlus
00313            : &Image_window::show_scaled8to16_BilinearPlus;
00314       }
00315       else
00316             show_scaled = &Image_window::show_scaled8to32_BilinearPlus;
00317 
00318       uses_palette = false;
00319     }
00320     else
00321     {
00322       cout << "Couldn't create scaled surface" << endl;
00323       delete surface;
00324       delete scaled_surface;
00325       surface = scaled_surface = 0;
00326     }
00327 
00328   }
00329   else if (scale == 2 && scaler == SuperEagle)
00330   {
00331     int hwdepth;
00332     
00333     if ( SDL_VideoModeOK(w, h, 32, flags))
00334       hwdepth = 32;
00335     else if ( SDL_VideoModeOK(w, h, 16, flags))
00336       hwdepth = 16;
00337     else
00338       hwdepth = Get_best_depth();
00339 
00340     if ((hwdepth != 16 && hwdepth != 32) || ibuf->depth != 8)
00341       cout << "Doubling from " << ibuf->depth << "bits to "
00342         << hwdepth << " not yet supported." << endl;
00343     else if ((scaled_surface = SDL_SetVideoMode(2*w, 2*h, 
00344             hwdepth, flags)) != 0 &&
00345        (unscaled_surface = surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
00346               8, 0, 0, 0, 0)) != 0)
00347     {     // Get color mask info.
00348       SDL_PixelFormat *fmt = scaled_surface->format;
00349       uint32 r = fmt->Rmask, g=fmt->Gmask, b=fmt->Bmask;
00350       if (hwdepth == 16)
00351       {
00352         show_scaled = (r == 0xf800 && g == 0x7e0 &&b == 0x1f) ? 
00353           &Image_window::show_scaled8to565_SuperEagle
00354            : (r == 0x7c00 && g == 0x3e0 && b == 0x1f) ?
00355           &Image_window::show_scaled8to555_SuperEagle
00356            : &Image_window::show_scaled8to16_SuperEagle;
00357       }
00358       else
00359             show_scaled = &Image_window::show_scaled8to32_SuperEagle;
00360 
00361       uses_palette = false;
00362     }
00363     else
00364     {
00365       cout << "Couldn't create scaled surface" << endl;
00366       delete surface;
00367       delete scaled_surface;
00368       surface = scaled_surface = 0;
00369     }
00370   }
00371   else if (scale == 2 && scaler == Super2xSaI)
00372   {
00373     int hwdepth;
00374     
00375     if ( SDL_VideoModeOK(w, h, 32, flags))
00376       hwdepth = 32;
00377     else if ( SDL_VideoModeOK(w, h, 16, flags))
00378       hwdepth = 16;
00379     else
00380       hwdepth = Get_best_depth();
00381 
00382     if ((hwdepth != 16 && hwdepth != 32) || ibuf->depth != 8)
00383       cout << "Doubling from " << ibuf->depth << "bits to "
00384         << hwdepth << " not yet supported." << endl;
00385     else if ((scaled_surface = SDL_SetVideoMode(2*w, 2*h, 
00386             hwdepth, flags)) != 0 &&
00387        (unscaled_surface = surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
00388               8, 0, 0, 0, 0)) != 0)
00389     {     // Get color mask info.
00390       SDL_PixelFormat *fmt = scaled_surface->format;
00391       uint32 r = fmt->Rmask, g=fmt->Gmask, b=fmt->Bmask;
00392       if (hwdepth == 16)
00393       {
00394         show_scaled = (r == 0xf800 && g == 0x7e0 &&b == 0x1f) ? 
00395           &Image_window::show_scaled8to565_Super2xSaI
00396            : (r == 0x7c00 && g == 0x3e0 && b == 0x1f) ?
00397           &Image_window::show_scaled8to555_Super2xSaI
00398            : &Image_window::show_scaled8to16_Super2xSaI;
00399       }
00400       else
00401             show_scaled = &Image_window::show_scaled8to32_Super2xSaI;
00402 
00403       uses_palette = false;
00404     }
00405     else
00406     {
00407       cout << "Couldn't create scaled surface" << endl;
00408       delete surface;
00409       delete scaled_surface;
00410       surface = scaled_surface = 0;
00411     }
00412   }
00413   else if (scale >= 2 && scaler == interlaced)
00414   {
00415     surface = SDL_SetVideoMode(w*scale, h*scale, ibuf->depth, flags);
00416     unscaled_surface = scaled_surface = 
00417         SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
00418               8, 0, 0, 0, 0);
00419     if (surface && scaled_surface)
00420     {
00421       show_scaled = &Image_window::show_scaled_interlace;
00422       ibuf->bits = (unsigned char *) scaled_surface->pixels;
00423           // Update line size in words.
00424       ibuf->line_width = scaled_surface->pitch/ibuf->pixel_size;
00425       return true;
00426     }
00427     else
00428     {
00429       cout << "Couldn't create 8bit scaled surface" << endl;
00430       if (surface) delete surface;
00431       if (scaled_surface) delete scaled_surface;
00432       surface = scaled_surface = 0;
00433     }
00434   }
00435   else if (scale == 2 && scaler == Scale2x)
00436   {
00437     surface = SDL_SetVideoMode(w*scale, h*scale, ibuf->depth, flags);
00438     unscaled_surface = scaled_surface = 
00439         SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
00440               8, 0, 0, 0, 0);
00441     if (surface && scaled_surface)
00442     {
00443       show_scaled = &Image_window::show_scale2x_noblur;
00444       ibuf->bits = (unsigned char *) scaled_surface->pixels;
00445           // Update line size in words.
00446       ibuf->line_width = scaled_surface->pitch/ibuf->pixel_size;
00447       return true;
00448     }
00449     else
00450     {
00451       cout << "Couldn't create 8bit scaled surface" << endl;
00452       if (surface) delete surface;
00453       if (scaled_surface) delete scaled_surface;
00454       surface = scaled_surface = 0;
00455     }
00456   }
00457   else if (scale >= 2)
00458   {
00459     surface = SDL_SetVideoMode(w*scale, h*scale, ibuf->depth, flags);
00460     unscaled_surface = scaled_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
00461               8, 0, 0, 0, 0);
00462     if (surface && scaled_surface)
00463     {
00464       show_scaled = &Image_window::show_scaled_point;
00465       ibuf->bits = (unsigned char *) scaled_surface->pixels;
00466           // Update line size in words.
00467       ibuf->line_width = scaled_surface->pitch/ibuf->pixel_size;
00468       return true;
00469     }
00470     else
00471     {
00472       cout << "Couldn't create 8bit scaled surface" << endl;
00473       if (surface) delete surface;
00474       if (scaled_surface) delete scaled_surface;
00475       surface = scaled_surface = 0;
00476     }
00477   }
00478 
00479   return false;
00480 }
00481 
00482 /*
00483  *  Free the surface.
00484  */
00485 
00486 void Image_window::free_surface
00487   (
00488   )
00489   {
00490   if (!surface)
00491     return;
00492   SDL_FreeSurface(surface);
00493   ibuf->bits = 0;
00494   surface = 0;
00495   if (scaled_surface)
00496     {
00497     SDL_FreeSurface(scaled_surface);
00498     scaled_surface = 0;
00499     }
00500   }
00501 
00502 /*
00503  *  Create a compatible buffer.
00504  */
00505 
00506 Image_buffer *Image_window::create_buffer
00507   (
00508   int w, int h      // Dimensions.
00509   )
00510   {
00511   Image_buffer *newbuf = ibuf->create_another(w, h);
00512   return (newbuf);
00513   }
00514 
00515 /*
00516  *  Window was resized.
00517  */
00518 
00519 void Image_window::resized
00520   (
00521   unsigned int neww, 
00522   unsigned int newh,
00523   int newsc,
00524   int newscaler
00525   )
00526   {
00527   if (surface)
00528     {
00529     if (neww == ibuf->width && newh == ibuf->height && newsc == scale && scaler == newscaler)
00530       return;   // Nothing changed.
00531     free_surface();   // Delete old image.
00532     }
00533   scale = newsc;
00534   scaler = newscaler;
00535   create_surface(neww, newh); // Create new one.
00536   }
00537 
00538 /*
00539  *  Repaint window.
00540  */
00541 
00542 void Image_window::show
00543   (
00544   )
00545   {
00546   if (!ready())
00547     return;
00548 
00549   if (show_scaled)    // 2X scaling?
00550     (this->*show_scaled)(0, 0, ibuf->width, ibuf->height);
00551   else
00552     SDL_UpdateRect(surface, 0, 0, ibuf->width, ibuf->height);
00553   }
00554 
00555 /*
00556  *  Repaint portion of window.
00557  */
00558 
00559 void Image_window::show
00560   (
00561   int x, int y, int w, int h
00562   )
00563   {
00564   if (!ready())
00565     return;
00566 
00567   int srcx = 0, srcy = 0;
00568   if (!ibuf->clip(srcx, srcy, w, h, x, y))
00569     return;
00570   if (show_scaled)    // 2X scaling?
00571     (this->*show_scaled)(x, y, w, h);
00572   else
00573     SDL_UpdateRect(surface, x, y, w, h);
00574   }
00575 
00576 
00577 /*
00578  *  Toggle fullscreen.
00579  */
00580 void Image_window::toggle_fullscreen() {
00581         Uint32 flags;
00582         int w, h, bpp;
00583 
00584   SDL_Surface *surf = scaled_surface&&surface==unscaled_surface?scaled_surface:surface;
00585 
00586         w = unscaled_surface->w;
00587         h = unscaled_surface->h;
00588         bpp = surf->format->BitsPerPixel;
00589 
00590         if ( fullscreen ) {
00591     cout << "Switching to windowed mode."<<endl;
00592                 flags = surf->flags & ~SDL_FULLSCREEN;
00593         } else {
00594     cout << "Switching to fullscreen mode."<<endl;
00595                 flags = surf->flags | SDL_FULLSCREEN;
00596         }
00597           // First see if it's allowed.
00598         if ( SDL_VideoModeOK(w, h, bpp, flags) )
00599     {
00600     free_surface();   // Delete old.
00601     fullscreen = !fullscreen;
00602     create_surface(w, h); // Create new.
00603     }
00604 }
00605 
00606 bool Image_window::screenshot(SDL_RWops *dst)
00607 {
00608   if (!surface) return false;
00609   return SavePCX_RW(unscaled_surface, dst, true);
00610 }
00611 
00612 void Image_window::set_title(const char *title)
00613 {
00614   SDL_WM_SetCaption(title, 0);
00615 }
00616 
00617 #ifdef HAVE_OPENGL
00618 /*
00619  *  Fill a rectangle with an 8-bit value.
00620  */
00621 
00622 void Image_window::opengl_fill8
00623   (
00624   unsigned char pix,
00625   int srcw, int srch,
00626   int destx, int desty
00627   )
00628   {
00629   SDL_Color *colors = surface->format->palette->colors;
00630   SDL_Color& color = colors[pix];
00631   glDisable(GL_TEXTURE_2D); // Disable texture-mapping.
00632   glPushMatrix();
00633   int x = destx;      // Left edge.
00634   int y = -(desty + srch);
00635   glTranslatef(x, y, 0);
00636   glBegin(GL_QUADS);
00637     {
00638     glColor3ub(color.r, color.g, color.b);
00639     glVertex3i(0, 0, 0);
00640     glVertex3i(srcw, 0, 0);
00641     glVertex3i(srcw, srch, 0);
00642     glVertex3i(0, srch, 0);
00643     }
00644   glEnd();
00645   glPopMatrix();
00646   }
00647 
00648 /*
00649  *  Apply a translucency table to a rectangle.
00650  */
00651 
00652 void Image_window::opengl_fill_translucent8
00653   (
00654   unsigned char /* val */,  // Not used.
00655   int srcw, int srch,
00656   int destx, int desty,
00657   Xform_palette& xform    // Transform table.
00658   )
00659   {
00660   glDisable(GL_TEXTURE_2D); // Disable texture-mapping.
00661   int x = destx;      // Left edge.
00662   int y = -(desty + srch);
00663   glBegin(GL_QUADS);
00664     {
00665     glColor4ub(xform.r, xform.g, xform.b, xform.a);
00666     glVertex2i(x, y);
00667     glVertex2i(x + srcw, y);
00668     glVertex2i(x + srcw, y + srch);
00669     glVertex2i(x, y + srch);
00670     }
00671   glEnd();
00672   }
00673 
00674 #endif
00675 

Generated on Mon Jul 9 14:42:47 2007 for ExultEngine by  doxygen 1.5.1