Adonthell 0.4
|
00001 /* 00002 $Id: image.cc,v 1.16 2004/10/25 06:55:01 ksterker Exp $ 00003 00004 Copyright (C) 1999/2000/2001/2002/2004 Alexandre Courbot 00005 Part of the Adonthell Project http://adonthell.linuxgames.com 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License. 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY. 00011 00012 See the COPYING file for more details. 00013 */ 00014 00015 00016 /** 00017 * @file image.cc 00018 * @author Alexandre Courbot <alexandrecourbot@linuxgames.com> 00019 * 00020 * @brief Defines the image class. 00021 * 00022 * 00023 */ 00024 00025 #include <SDL/SDL_endian.h> 00026 #include "image.h" 00027 #include "pnm.h" 00028 00029 #if SDL_BYTEORDER == SDL_BIG_ENDIAN 00030 #define R_MASK 0x00ff0000 00031 #define G_MASK 0x0000ff00 00032 #define B_MASK 0x000000ff 00033 #define A_MASK 0xff000000 00034 #else 00035 #define R_MASK 0x000000ff 00036 #define G_MASK 0x0000ff00 00037 #define B_MASK 0x00ff0000 00038 #define A_MASK 0xff000000 00039 #endif 00040 00041 using namespace std; 00042 00043 image::image () : surface () 00044 { 00045 } 00046 00047 image::image (u_int16 l, u_int16 h, bool mode) : surface (mode) 00048 { 00049 resize (l, h); 00050 } 00051 00052 image::image (SDL_Surface *s, const SDL_Color & color) : surface (false) 00053 { 00054 if (screen::dbl_mode ()) { 00055 set_length (s->w >> 1); 00056 set_height (s->h >> 1); 00057 } else { 00058 set_length (s->w); 00059 set_height (s->h); 00060 } 00061 00062 vis = SDL_DisplayFormat (s); 00063 SDL_SetColorKey (vis, SDL_SRCCOLORKEY | SDL_RLEACCEL, 00064 SDL_MapRGB (vis->format, color.r, color.g, color.b)); 00065 SDL_FreeSurface (s); 00066 changed = false; 00067 } 00068 00069 image::~image () 00070 { 00071 } 00072 00073 void image::resize (u_int16 l, u_int16 h) 00074 { 00075 surface::resize (l, h); 00076 } 00077 00078 void image::clear () 00079 { 00080 surface::clear (); 00081 } 00082 00083 s_int8 image::get (igzstream& file) 00084 { 00085 s_int8 ret; 00086 00087 u_int8 m; 00088 u_int8 a; 00089 00090 m << file; 00091 a << file; 00092 00093 ret = get_raw (file); 00094 if (!ret) 00095 { 00096 set_mask (m); 00097 set_alpha (a); 00098 } 00099 return ret; 00100 } 00101 00102 s_int8 image::load (string fname) 00103 { 00104 igzstream file (fname); 00105 s_int8 ret = 0; 00106 00107 if (!file.is_open ()) 00108 return 1; 00109 ret = get (file); 00110 file.close (); 00111 return ret; 00112 } 00113 00114 s_int8 image::get_raw (igzstream& file) 00115 { 00116 void * rawdata; 00117 00118 u_int16 l, h; 00119 00120 clear (); 00121 00122 l << file; 00123 h << file; 00124 00125 rawdata = new char[l * h * 3]; 00126 file.get_block (rawdata, l * h * 3); 00127 00128 raw2display (rawdata, l, h); 00129 00130 delete[] (char *) rawdata; 00131 00132 if (!vis) return -1; 00133 00134 changed = true; 00135 return 0; 00136 } 00137 00138 00139 s_int8 image::load_raw (string fname) 00140 { 00141 igzstream file (fname); 00142 s_int8 ret = 0; 00143 00144 if (!file.is_open ()) 00145 return 1; 00146 ret = get_raw (file); 00147 file.close (); 00148 return ret; 00149 } 00150 00151 00152 s_int8 image::get_pnm (SDL_RWops * file) 00153 { 00154 void *rawdata; 00155 u_int16 l, h; 00156 00157 clear (); 00158 00159 rawdata = pnm::get (file, &l, &h); 00160 00161 raw2display (rawdata, l, h); 00162 00163 free (rawdata); 00164 00165 if (!vis) return -1; 00166 00167 changed = true; 00168 return 0; 00169 } 00170 00171 00172 s_int8 image::load_pnm (string fname) 00173 { 00174 SDL_RWops *file; 00175 s_int8 ret = 0; 00176 00177 file = SDL_RWFromFile (fname.c_str (), "rb"); 00178 if (!file) 00179 return 1; 00180 ret = get_pnm (file); 00181 SDL_RWclose (file); 00182 return ret; 00183 } 00184 00185 s_int8 image::put (ogzstream& file) const 00186 { 00187 bool m = is_masked (); 00188 s_int8 a = alpha (); 00189 00190 m >> file; 00191 a >> file; 00192 00193 put_raw (file); 00194 00195 return 0; 00196 } 00197 00198 s_int8 image::save (string fname) const 00199 { 00200 ogzstream file (fname); 00201 s_int8 ret = 0; 00202 00203 if (!file.is_open ()) 00204 return 1; 00205 ret = put (file); 00206 file.close (); 00207 return ret; 00208 } 00209 00210 s_int8 image::put_raw (ogzstream& file) const 00211 { 00212 length () >> file; 00213 height () >> file; 00214 00215 if (!length () || !height ()) return 0; 00216 00217 SDL_Surface *tmp2 = SDL_CreateRGBSurface (0, 1, 1, 24, 00218 R_MASK, G_MASK, 00219 B_MASK, 0); 00220 00221 image * imt; 00222 SDL_Surface * toconvert; 00223 00224 if (dbl_mode) 00225 { 00226 imt = new image(); 00227 imt->double_size(*this); 00228 toconvert = imt->vis; 00229 } 00230 else 00231 { 00232 toconvert = vis; 00233 } 00234 00235 SDL_Surface * temp = SDL_ConvertSurface (toconvert, tmp2->format, 0); 00236 00237 SDL_LockSurface (temp); 00238 00239 // The pitch is ALWAYS a multiple of 4, no matter the length of the image. 00240 // We must be carefull not to record the pitch overlap. 00241 for (u_int16 j = 0; j < height (); j++) 00242 { 00243 file.put_block ((u_int8 *) temp->pixels + (temp->pitch * j), length () * 3); 00244 } 00245 00246 SDL_UnlockSurface (temp); 00247 00248 SDL_FreeSurface (temp); 00249 SDL_FreeSurface (tmp2); 00250 if (dbl_mode) delete imt; 00251 return 0; 00252 } 00253 00254 s_int8 image::save_raw (string fname) const 00255 { 00256 ogzstream file (fname); 00257 s_int8 ret = 0; 00258 00259 if (!file.is_open ()) 00260 return 1; 00261 ret = put_raw (file); 00262 file.close (); 00263 return ret; 00264 } 00265 00266 s_int8 image::put_pnm (SDL_RWops * file) const 00267 { 00268 SDL_Surface *tmp2 = SDL_CreateRGBSurface (0, 1, 1, 24, 00269 R_MASK, G_MASK, 00270 B_MASK, 0); 00271 00272 SDL_Surface * temp; 00273 00274 if (dbl_mode) 00275 { 00276 image imt; 00277 imt.half_size(*this); 00278 temp = SDL_ConvertSurface (imt.vis, tmp2->format, 0); 00279 } 00280 else 00281 { 00282 temp = SDL_ConvertSurface (vis, tmp2->format, 0); 00283 } 00284 00285 pnm::put (file, temp->pixels, length (), height ()); 00286 00287 SDL_FreeSurface (temp); 00288 SDL_FreeSurface (tmp2); 00289 00290 return 0; 00291 } 00292 00293 s_int8 image::save_pnm (string fname) const 00294 { 00295 SDL_RWops *file; 00296 s_int8 ret = 0; 00297 00298 file = SDL_RWFromFile (fname.c_str (), "wb"); 00299 if (!file) 00300 return 1; 00301 ret = put_pnm (file); 00302 SDL_RWclose (file); 00303 return ret; 00304 } 00305 00306 void image::zoom (const surface& src, u_int16 l, u_int16 h, u_int16 x, u_int16 y) 00307 { 00308 // Calculate the step per pixel. 00309 // While the surface positions are u_int16s, we use u_int32s for step 00310 // and position during zoom, that we'll divide by 65535 ( >> 16). That 00311 // way, we can perform our zoom without having to divide two times per 00312 // pixel we proceed (we can replace the divides with shift, much much 00313 // faster. 00314 u_int32 xstep = (u_int32) (((double) src.length () / (double) l) * 65535); 00315 u_int32 ystep = (u_int32) (((double) src.height () / (double) h) * 65535); 00316 u_int32 xcur; 00317 u_int32 ycur; 00318 00319 u_int32 col; 00320 00321 lock (); 00322 src.lock (); 00323 ycur = 0; 00324 u_int16 i, j; 00325 for (j = y; j < h + y; j++) 00326 { 00327 xcur = 0; 00328 for (i = x; i < l + x; i++) 00329 { 00330 src.get_pix (xcur >> 16, ycur >> 16, col); 00331 put_pix (i, j, col); 00332 xcur += xstep; 00333 } 00334 ycur += ystep; 00335 } 00336 src.unlock (); 00337 unlock (); 00338 } 00339 00340 void image::tile (const surface& src, u_int16 l, u_int16 h, u_int16 x, u_int16 y) 00341 { 00342 u_int16 posx; 00343 u_int16 posy; 00344 00345 drawing_area da (x, y, l, h); 00346 00347 for (posy = 0; posy < h; posy += src.height ()) 00348 for (posx = 0; posx < l; posx += src.length ()) 00349 src.draw (x + posx, y + posy, &da, this); 00350 } 00351 00352 void image::brightness (const surface& src, u_int8 cont, bool proceed_mask) 00353 { 00354 u_int16 i, j; 00355 u_int8 ir, ig, ib; 00356 u_int32 temp = 0; 00357 00358 if (screen::dbl_mode () && !dbl_mode) resize (src.length () << 1, src.height () << 1); 00359 else resize (src.length (), src.height ()); 00360 00361 lock (); 00362 src.lock (); 00363 for (j = 0; j < height (); j++) 00364 for (i = 0; i < length (); i++) 00365 { 00366 src.get_pix (i, j, temp); 00367 if ((proceed_mask) || temp != screen::trans_col ()) 00368 { 00369 src.get_pix (i, j, ir, ig, ib); 00370 ir = (ir * cont) >> 8; 00371 ig = (ig * cont) >> 8; 00372 ib = (ib * cont) >> 8; 00373 put_pix (i, j, ir, ig, ib); 00374 } 00375 else put_pix (i, j, temp); 00376 } 00377 src.unlock (); 00378 unlock (); 00379 00380 set_mask (false); 00381 set_alpha (255); 00382 } 00383 00384 image& image::operator = (const image& src) 00385 { 00386 (surface&) (*this) = (surface&) src; 00387 return *this; 00388 } 00389 00390 00391 00392 00393 // Private methods 00394 00395 00396 00397 void image::raw2display (void * rawdata, u_int16 l, u_int16 h) 00398 { 00399 set_length (l); 00400 set_height (h); 00401 00402 SDL_Surface *tmp2 = SDL_CreateRGBSurfaceFrom (rawdata, length (), 00403 height (), 24, 00404 length () * 3, 00405 R_MASK, G_MASK, 00406 B_MASK, 0); 00407 vis = SDL_DisplayFormat (tmp2); 00408 if (dbl_mode) 00409 { 00410 image imt; 00411 imt.double_size(*this); 00412 *this = imt; 00413 } 00414 SDL_FreeSurface (tmp2); 00415 }