00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
00085
00086 static int Get_best_depth
00087 (
00088 )
00089 {
00090
00091 const SDL_VideoInfo *vinfo = SDL_GetVideoInfo();
00092
00093 return (vinfo->vfmt->BitsPerPixel);
00094 }
00095
00096
00097
00098
00099
00100 Image_window::~Image_window
00101 (
00102 )
00103 {
00104 free_surface();
00105 delete ibuf;
00106 }
00107
00108
00109
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;
00128 #else
00129 if (try_scaler(w, h, flags)) return;
00130 #endif
00131
00132 if (!surface)
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
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
00152 if (scaler ==OpenGL)
00153 {
00154 #ifdef HAVE_OPENGL
00155
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
00164 int video_flags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER |
00165 SDL_HWPALETTE | SDL_RESIZABLE |
00166 (flags&SDL_FULLSCREEN);
00167
00168 if (vinfo->hw_available)
00169 video_flags |= SDL_HWSURFACE;
00170 else
00171 video_flags |= SDL_SWSURFACE;
00172 if (vinfo->blit_hw)
00173 video_flags |= SDL_HWACCEL;
00174
00175 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
00176
00177 int hwdepth = vinfo->vfmt->BitsPerPixel;
00178
00179
00180
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
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 {
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)
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 {
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)
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 {
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 {
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 {
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
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
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
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
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
00504
00505
00506 Image_buffer *Image_window::create_buffer
00507 (
00508 int w, int h
00509 )
00510 {
00511 Image_buffer *newbuf = ibuf->create_another(w, h);
00512 return (newbuf);
00513 }
00514
00515
00516
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;
00531 free_surface();
00532 }
00533 scale = newsc;
00534 scaler = newscaler;
00535 create_surface(neww, newh);
00536 }
00537
00538
00539
00540
00541
00542 void Image_window::show
00543 (
00544 )
00545 {
00546 if (!ready())
00547 return;
00548
00549 if (show_scaled)
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
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)
00571 (this->*show_scaled)(x, y, w, h);
00572 else
00573 SDL_UpdateRect(surface, x, y, w, h);
00574 }
00575
00576
00577
00578
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
00598 if ( SDL_VideoModeOK(w, h, bpp, flags) )
00599 {
00600 free_surface();
00601 fullscreen = !fullscreen;
00602 create_surface(w, h);
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
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);
00632 glPushMatrix();
00633 int x = destx;
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
00650
00651
00652 void Image_window::opengl_fill_translucent8
00653 (
00654 unsigned char ,
00655 int srcw, int srch,
00656 int destx, int desty,
00657 Xform_palette& xform
00658 )
00659 {
00660 glDisable(GL_TEXTURE_2D);
00661 int x = destx;
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