Adonthell 0.4
|
00001 /* 00002 $Id: surface.cc,v 1.15 2004/10/25 06:55:01 ksterker Exp $ 00003 00004 Copyright (C) 1999/2000/2001/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 surface.cc 00018 * Defines the surface class. 00019 */ 00020 00021 #include "surface.h" 00022 #include "screen.h" 00023 00024 #include <iostream> 00025 00026 using namespace std; 00027 00028 00029 SDL_Rect surface::srcrect; 00030 SDL_Rect surface::dstrect; 00031 00032 void surface::resize_aux (u_int16 l, u_int16 h) 00033 { 00034 if (l == length () && h == height ()) return; 00035 00036 if (vis) SDL_FreeSurface (vis); 00037 00038 set_length (l); 00039 set_height (h); 00040 00041 vis = SDL_CreateRGBSurface (SDL_SRCCOLORKEY | SDL_SRCALPHA | SDL_ASYNCBLIT, 00042 l, h, 00043 screen::bytes_per_pixel () * 8, 00044 screen::display.vis->format->Rmask, 00045 screen::display.vis->format->Gmask, 00046 screen::display.vis->format->Bmask, 00047 screen::display.vis->format->Amask); 00048 changed = true; 00049 } 00050 00051 void surface::double_size(const surface & src) 00052 { 00053 u_int32 col; 00054 00055 lock (); 00056 src.lock (); 00057 00058 dbl_mode = src.is_dbl_mode (); 00059 resize(src.length(), src.height()); 00060 for (u_int16 j = 0; j < height(); j++) 00061 for (u_int16 i = 0; i < length(); i++) 00062 { 00063 src.get_pix_aux(i, j, col); 00064 put_pix(i, j, col); 00065 } 00066 00067 src.unlock (); 00068 unlock (); 00069 } 00070 00071 void surface::half_size(const surface & src) 00072 { 00073 u_int32 col; 00074 00075 lock (); 00076 src.lock (); 00077 00078 dbl_mode = src.is_dbl_mode (); 00079 resize_aux(src.length(), src.height()); 00080 for (u_int16 j = 0; j < src.height() - 1; j++) 00081 for (u_int16 i = 0; i < src.length() - 1; i++) 00082 { 00083 src.get_pix(i, j, col); 00084 put_pix_aux(i, j, col); 00085 } 00086 00087 src.unlock (); 00088 unlock (); 00089 } 00090 00091 void surface::get_pix_aux (u_int16 x, u_int16 y, u_int32& col) const 00092 { 00093 u_int8 * offset = ((Uint8 *) vis->pixels) + y * vis->pitch 00094 + x * vis->format->BytesPerPixel; 00095 00096 switch (vis->format->BytesPerPixel) 00097 { 00098 case 1: 00099 col = *((Uint8 *)(offset)); 00100 break; 00101 case 2: 00102 col = *((Uint16 *)(offset)); 00103 break; 00104 case 3: 00105 { 00106 u_int8 r, g, b; 00107 col = 0; 00108 u_int32 t; 00109 00110 r = *((offset) + (vis->format->Rshift >> 3)); 00111 g = *((offset) + (vis->format->Gshift >> 3)); 00112 b = *((offset) + (vis->format->Bshift >> 3)); 00113 00114 t = r << vis->format->Rshift; 00115 col |= t; 00116 t = g << vis->format->Gshift; 00117 col |= t; 00118 t = b << vis->format->Bshift; 00119 col |= t; 00120 00121 break; 00122 } 00123 case 4: 00124 col = *((Uint32 *)(offset)); 00125 break; 00126 } 00127 } 00128 00129 void surface::put_pix_aux (u_int16 x, u_int16 y, u_int32 col) 00130 { 00131 u_int8 * offset = ((Uint8 *) vis->pixels) + y * vis->pitch 00132 + x*vis->format->BytesPerPixel; 00133 00134 switch (vis->format->BytesPerPixel) 00135 { 00136 case 2: 00137 *((Uint16 *) (offset)) = (Uint16) col; 00138 if (dbl_mode) 00139 { 00140 *((Uint16 *) (offset+vis->format->BytesPerPixel)) = (Uint16) col; 00141 *((Uint16 *) (offset+vis->pitch)) = (Uint16) col; 00142 *((Uint16 *) (offset+vis->pitch+vis->format->BytesPerPixel)) = (Uint16) col; 00143 } 00144 break; 00145 case 3: 00146 { 00147 u_int8 r, g, b; 00148 00149 r = (col >> vis->format->Rshift); 00150 g = (col >> vis->format->Gshift); 00151 b = (col >> vis->format->Bshift); 00152 *((offset) + (vis->format->Rshift >> 3)) = r; 00153 *((offset) + (vis->format->Gshift >> 3)) = g; 00154 *((offset) + (vis->format->Bshift >> 3)) = b; 00155 if (dbl_mode) 00156 { 00157 *((offset+vis->format->BytesPerPixel) + (vis->format->Rshift >> 3)) = r; 00158 *((offset+vis->format->BytesPerPixel) + (vis->format->Gshift >> 3)) = g; 00159 *((offset+vis->format->BytesPerPixel) + (vis->format->Bshift >> 3)) = b; 00160 *((offset+vis->pitch) + (vis->format->Rshift >> 3)) = r; 00161 *((offset+vis->pitch) + (vis->format->Gshift >> 3)) = g; 00162 *((offset+vis->pitch) + (vis->format->Bshift >> 3)) = b; 00163 *((offset+vis->pitch+vis->format->BytesPerPixel) + (vis->format->Rshift >> 3)) = r; 00164 *((offset+vis->pitch+vis->format->BytesPerPixel) + (vis->format->Gshift >> 3)) = g; 00165 *((offset+vis->pitch+vis->format->BytesPerPixel) + (vis->format->Bshift >> 3)) = b; 00166 } 00167 break; 00168 } 00169 case 4: 00170 *((Uint32 *)(offset)) = (Uint32) col; 00171 if (dbl_mode) 00172 { 00173 *((Uint32 *) (offset+vis->format->BytesPerPixel)) = (Uint32) col; 00174 *((Uint32 *) (offset+vis->pitch)) = (Uint32) col; 00175 *((Uint32 *) (offset+vis->pitch+vis->format->BytesPerPixel)) = (Uint32) col; 00176 } 00177 break; 00178 } 00179 changed = true; 00180 } 00181 00182 00183 surface::surface (bool mode) : drawable () 00184 { 00185 vis = NULL; 00186 alpha_ = 255; 00187 mask_on = false; 00188 not_screen = true; 00189 changed = false; 00190 dbl_mode = mode ? screen::dbl_mode () : false; 00191 } 00192 00193 surface::~surface () 00194 { 00195 if (vis && not_screen) SDL_FreeSurface (vis); 00196 } 00197 00198 void surface::set_mask (bool m) 00199 { 00200 if (m != is_masked ()) 00201 { 00202 mask_on = m; 00203 changed = true; 00204 } 00205 } 00206 00207 00208 void surface::set_alpha (u_int8 t) 00209 { 00210 if ((t == 255) && (alpha_ != 255) && vis) 00211 SDL_SetAlpha (vis, 0, 0); 00212 alpha_ = t; 00213 } 00214 00215 void surface::draw (s_int16 x, s_int16 y, s_int16 sx, s_int16 sy, u_int16 sl, 00216 u_int16 sh, const drawing_area * da_opt, 00217 surface * target) const 00218 { 00219 if (target == NULL) target = &screen::display; 00220 00221 setup_rects (x, y, sx, sy, sl, sh, da_opt); 00222 00223 if (screen::dbl_mode()) 00224 { 00225 x <<= 1; 00226 y <<= 1; 00227 sx <<= 1; 00228 sy <<= 1; 00229 sl <<= 1; 00230 sh <<= 1; 00231 srcrect.x <<= 1; 00232 srcrect.y <<= 1; 00233 srcrect.w <<= 1; 00234 srcrect.h <<= 1; 00235 dstrect.x <<= 1; 00236 dstrect.y <<= 1; 00237 dstrect.w <<= 1; 00238 dstrect.h <<= 1; 00239 } 00240 00241 if (!dstrect.w || !dstrect.h) 00242 return; 00243 00244 if (changed) 00245 { 00246 changed = false; 00247 if (is_masked ()) 00248 SDL_SetColorKey (vis, SDL_SRCCOLORKEY | SDL_RLEACCEL, screen::trans_col ()); 00249 else 00250 SDL_SetColorKey (vis, 0, 0); 00251 } 00252 00253 if (alpha () != 255) 00254 SDL_SetAlpha (vis, SDL_SRCALPHA, alpha_); 00255 00256 SDL_BlitSurface (vis, &srcrect, target->vis, &dstrect); 00257 target->changed = true; 00258 } 00259 00260 void surface::fillrect (s_int16 x, s_int16 y, u_int16 l, u_int16 h, u_int32 col, 00261 drawing_area * da_opt) 00262 { 00263 if (da_opt) 00264 { 00265 dstrect = da_opt->setup_rects (); 00266 } 00267 else 00268 { 00269 dstrect.x = x; 00270 dstrect.y = y; 00271 dstrect.w = l; 00272 dstrect.h = h; 00273 } 00274 00275 if (screen::dbl_mode ()) 00276 { 00277 dstrect.x <<= 1; 00278 dstrect.y <<= 1; 00279 dstrect.w <<= 1; 00280 dstrect.h <<= 1; 00281 } 00282 00283 SDL_FillRect (vis, &dstrect, col); 00284 changed = true; 00285 } 00286 00287 void surface::lock () const 00288 { 00289 if (!length () || !height ()) return; 00290 if (SDL_MUSTLOCK(vis)) 00291 SDL_LockSurface (vis); 00292 } 00293 00294 void surface::unlock () const 00295 { 00296 if (!length () || !height ()) return; 00297 if (SDL_MUSTLOCK(vis)) 00298 SDL_UnlockSurface (vis); 00299 } 00300 00301 void surface::put_pix (u_int16 x, u_int16 y, u_int32 col) 00302 { 00303 if (dbl_mode) 00304 { 00305 x <<= 1; 00306 y <<= 1; 00307 } 00308 00309 u_int8 * offset = ((Uint8 *) vis->pixels) + y * vis->pitch 00310 + x*vis->format->BytesPerPixel; 00311 00312 switch (vis->format->BytesPerPixel) 00313 { 00314 case 2: 00315 *((Uint16 *) (offset)) = (Uint16) col; 00316 if (dbl_mode) 00317 { 00318 *((Uint16 *) (offset+vis->format->BytesPerPixel)) = (Uint16) col; 00319 *((Uint16 *) (offset+vis->pitch)) = (Uint16) col; 00320 *((Uint16 *) (offset+vis->pitch+vis->format->BytesPerPixel)) = (Uint16) col; 00321 } 00322 break; 00323 case 3: 00324 { 00325 u_int8 r, g, b; 00326 00327 r = (col >> vis->format->Rshift); 00328 g = (col >> vis->format->Gshift); 00329 b = (col >> vis->format->Bshift); 00330 *((offset) + (vis->format->Rshift >> 3)) = r; 00331 *((offset) + (vis->format->Gshift >> 3)) = g; 00332 *((offset) + (vis->format->Bshift >> 3)) = b; 00333 if (dbl_mode) 00334 { 00335 *((offset+vis->format->BytesPerPixel) + (vis->format->Rshift >> 3)) = r; 00336 *((offset+vis->format->BytesPerPixel) + (vis->format->Gshift >> 3)) = g; 00337 *((offset+vis->format->BytesPerPixel) + (vis->format->Bshift >> 3)) = b; 00338 *((offset+vis->pitch) + (vis->format->Rshift >> 3)) = r; 00339 *((offset+vis->pitch) + (vis->format->Gshift >> 3)) = g; 00340 *((offset+vis->pitch) + (vis->format->Bshift >> 3)) = b; 00341 *((offset+vis->pitch+vis->format->BytesPerPixel) + (vis->format->Rshift >> 3)) = r; 00342 *((offset+vis->pitch+vis->format->BytesPerPixel) + (vis->format->Gshift >> 3)) = g; 00343 *((offset+vis->pitch+vis->format->BytesPerPixel) + (vis->format->Bshift >> 3)) = b; 00344 } 00345 break; 00346 } 00347 case 4: 00348 *((Uint32 *)(offset)) = (Uint32) col; 00349 if (dbl_mode) 00350 { 00351 *((Uint32 *) (offset+vis->format->BytesPerPixel)) = (Uint32) col; 00352 *((Uint32 *) (offset+vis->pitch)) = (Uint32) col; 00353 *((Uint32 *) (offset+vis->pitch+vis->format->BytesPerPixel)) = (Uint32) col; 00354 } 00355 break; 00356 } 00357 changed = true; 00358 } 00359 00360 void surface::get_pix (u_int16 x, u_int16 y, u_int32& col) const 00361 { 00362 if (dbl_mode) 00363 { 00364 x <<= 1; 00365 y <<= 1; 00366 } 00367 u_int8 * offset = ((Uint8 *) vis->pixels) + y * vis->pitch 00368 + x * vis->format->BytesPerPixel; 00369 00370 switch (vis->format->BytesPerPixel) 00371 { 00372 case 2: 00373 col = *((Uint16 *)(offset)); 00374 break; 00375 case 3: 00376 { 00377 u_int8 r, g, b; 00378 col = 0; 00379 u_int32 t; 00380 00381 r = *((offset) + (vis->format->Rshift >> 3)); 00382 g = *((offset) + (vis->format->Gshift >> 3)); 00383 b = *((offset) + (vis->format->Bshift >> 3)); 00384 00385 t = r << vis->format->Rshift; 00386 col |= t; 00387 t = g << vis->format->Gshift; 00388 col |= t; 00389 t = b << vis->format->Bshift; 00390 col |= t; 00391 00392 break; 00393 } 00394 case 4: 00395 col = *((Uint32 *)(offset)); 00396 break; 00397 } 00398 } 00399 00400 surface& surface::operator = (surface& src) 00401 { 00402 (drawable&) (*this) = (drawable&) src; 00403 mask_on = src.mask_on; 00404 alpha_ = src.alpha_; 00405 not_screen = src.not_screen; 00406 dbl_mode = src.dbl_mode; 00407 if (vis) SDL_FreeSurface (vis); 00408 if (!src.vis) 00409 vis = NULL; 00410 else 00411 vis = SDL_DisplayFormat (src.vis); 00412 changed = true; 00413 return *this; 00414 } 00415 00416 00417 00418 // Protected methods 00419 00420 00421 00422 void surface::resize (u_int16 l, u_int16 h) 00423 { 00424 if (l == length () && h == height ()) return; 00425 00426 if (vis) SDL_FreeSurface (vis); 00427 00428 set_length (l); 00429 set_height (h); 00430 00431 if (screen::dbl_mode ()) 00432 { 00433 l <<= 1; 00434 h <<= 1; 00435 } 00436 00437 vis = SDL_CreateRGBSurface (SDL_SRCCOLORKEY | SDL_SRCALPHA | SDL_ASYNCBLIT, 00438 l, h, 00439 screen::bytes_per_pixel () * 8, 00440 screen::display.vis->format->Rmask, 00441 screen::display.vis->format->Gmask, 00442 screen::display.vis->format->Bmask, 00443 screen::display.vis->format->Amask); 00444 changed = true; 00445 } 00446 00447 void surface::clear () 00448 { 00449 if (vis) 00450 { 00451 SDL_FreeSurface (vis); 00452 vis = NULL; 00453 set_length (0); 00454 set_height (0); 00455 set_alpha (255); 00456 set_mask (false); 00457 changed = true; 00458 } 00459 } 00460 00461 00462 00463 // Private methods 00464 00465 00466 00467 void surface::setup_rects (s_int16 x, s_int16 y, s_int16 sx, s_int16 sy, 00468 u_int16 sl, u_int16 sh, const drawing_area * draw_to) const 00469 { 00470 if (draw_to) 00471 { 00472 drawing_area im_zone (x, y, sl, sh); 00473 SDL_Rect tr = draw_to->setup_rects (); 00474 00475 drawing_area da_int; 00476 da_int = tr; 00477 00478 im_zone.assign_drawing_area (&da_int); 00479 tr = im_zone.setup_rects (); 00480 00481 dstrect = tr; 00482 srcrect = dstrect; 00483 srcrect.x = x < dstrect.x ? sx + dstrect.x - x : sx; 00484 srcrect.y = y < dstrect.y ? sy + dstrect.y - y : sy; 00485 } 00486 else 00487 { 00488 srcrect.x = sx; 00489 srcrect.y = sy; 00490 srcrect.w = sl; 00491 srcrect.h = sh; 00492 00493 dstrect = srcrect; 00494 00495 dstrect.x = x; 00496 dstrect.y = y; 00497 } 00498 }