00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "tileitem.h"
00021 #include <iostream>
00022 #include <SDL.h>
00023 #include <SDL_endian.h>
00024 #include "tile.h"
00025 #include "../game/config.h"
00026 #include "../include/app.h"
00027 #include "../map/camera.h"
00028 #include "../tool/error.h"
00029 #include "../tool/point.h"
00030 #include "../tool/stats.h"
00031 #ifdef DBG_TILE
00032 #include "../graphic/colors.h"
00033 #endif
00034
00035
00036 void TileItem_AlphaSoftware::Draw(const Point2i &pos){
00037 AppWormux::GetInstance()->video.window.Blit(GetSurface(),
00038 pos * CELL_SIZE - camera.GetPosition());
00039 }
00040
00041 void TileItem_Empty::Draw(const Point2i &pos)
00042 {
00043 #ifdef DBG_TILE
00044 AppWormux::GetInstance()->video.window.FillRect(Rectanglei(pos * CELL_SIZE - camera.GetPosition(),CELL_SIZE), c_red);
00045 #endif
00046 }
00047
00048 TileItem_AlphaSoftware::TileItem_AlphaSoftware(const Point2i &size){
00049 m_size = size;
00050 m_surface = Surface(size, SDL_SWSURFACE|SDL_SRCALPHA, true).DisplayFormatAlpha();
00051 need_delete = false;
00052 ResetEmptyCheck();
00053
00054 _GetAlpha = &TileItem_AlphaSoftware::GetAlpha_Generic;
00055 if( m_surface.GetBytesPerPixel() == 4 ){
00056 if( m_surface.GetSurface()->format->Amask == 0x000000ff ){
00057 if( SDL_BYTEORDER == SDL_LIL_ENDIAN )
00058 _GetAlpha = &TileItem_AlphaSoftware::GetAlpha_Index0;
00059 else
00060 _GetAlpha = &TileItem_AlphaSoftware::GetAlpha_Index3;
00061 }else{
00062 if( m_surface.GetSurface()->format->Amask == 0xff000000 ){
00063 if (SDL_BYTEORDER == SDL_LIL_ENDIAN )
00064 _GetAlpha = &TileItem_AlphaSoftware::GetAlpha_Index3;
00065 else
00066 _GetAlpha = &TileItem_AlphaSoftware::GetAlpha_Index0;
00067 }
00068 }
00069 }
00070 }
00071
00072 TileItem_AlphaSoftware::~TileItem_AlphaSoftware(){
00073 }
00074
00075 void TileItem_AlphaSoftware::ResetEmptyCheck()
00076 {
00077 need_check_empty = true;
00078 last_filled_pixel = m_surface.GetPixels();
00079 }
00080
00081 unsigned char TileItem_AlphaSoftware::GetAlpha(const Point2i &pos){
00082 return (this->*_GetAlpha)(pos);
00083 }
00084
00085 unsigned char TileItem_AlphaSoftware::GetAlpha_Index0 (const Point2i &pos){
00086 return *(m_surface.GetPixels() + pos.y*m_surface.GetPitch() + pos.x * 4 + 0);
00087 }
00088
00089 unsigned char TileItem_AlphaSoftware::GetAlpha_Index3 (const Point2i &pos){
00090 return *(m_surface.GetPixels() + pos.y*m_surface.GetPitch() + pos.x * 4 + 3);
00091 }
00092
00093 unsigned char TileItem_AlphaSoftware::GetAlpha_Generic (const Point2i &pos){
00094 unsigned char r, g, b, a;
00095
00096 Uint32 pixel = *(Uint32 *)(m_surface.GetPixels() + pos.y*m_surface.GetPitch() + pos.x*m_surface.GetBytesPerPixel());
00097 m_surface.GetRGBA(pixel, r, g, b, a);
00098
00099 return a;
00100 }
00101
00102 void TileItem_AlphaSoftware::Dig(const Point2i &position, const Surface& dig){
00103 need_check_empty = true;
00104 int starting_x = position.x >= 0 ? position.x : 0;
00105 int starting_y = position.y >= 0 ? position.y : 0;
00106 int ending_x = position.x+dig.GetWidth() <= m_surface.GetWidth() ? position.x+dig.GetWidth() : m_surface.GetWidth();
00107 int ending_y = position.y+dig.GetHeight() <= m_surface.GetHeight() ? position.y+dig.GetHeight() : m_surface.GetHeight();
00108
00109 for( int py = starting_y ; py < ending_y ; py++)
00110 for( int px = starting_x ; px < ending_x ; px++)
00111 if ( *(dig.GetPixels() + (py-position.y)*dig.GetPitch() + (px-position.x) * 4 + 3) != 0)
00112 *(m_surface.GetPixels() + py*m_surface.GetPitch() + px * 4 + 3) = 0;
00113 }
00114
00115 void TileItem_AlphaSoftware::Dig(const Point2i ¢er, const uint radius){
00116 need_check_empty = true;
00117 unsigned char* buf = m_surface.GetPixels();
00118 const uint line_size = m_surface.GetPitch();
00119 const uint bpp = m_surface.GetBytesPerPixel();
00120
00121 int y = (center.y - (int)radius - (int)EXPLOSION_BORDER_SIZE >= 0) ? (center.y - (int)radius - EXPLOSION_BORDER_SIZE) : 0;
00122 buf += y * line_size;
00123
00124
00125 while ( (uint) y <= center.y + radius + EXPLOSION_BORDER_SIZE&& y < CELL_SIZE.y )
00126 {
00127
00128 int dac = center.y - y;
00129
00130
00131 float angle = asin( (float)dac / (float)radius);
00132
00133
00134 int start_x, end_x, lenght;
00135 lenght = (int) ((float) radius * cos (angle));
00136 lenght = lenght > 0 ? lenght : - lenght;
00137 start_x = center.x - lenght;
00138 lenght *= 2;
00139 end_x = start_x + lenght;
00140 Empty(start_x, end_x, buf, bpp);
00141
00142
00143
00144 int bstart_x, bend_x, blenght;
00145 angle = asin( (float)dac / (float)(radius + EXPLOSION_BORDER_SIZE));
00146 blenght = (int) ((float) (radius + EXPLOSION_BORDER_SIZE) * cos (angle));
00147 blenght = blenght > 0 ? blenght : - blenght;
00148 bstart_x = center.x - blenght;
00149 bend_x = bstart_x + (blenght - lenght/2);
00150 Darken(bstart_x, bend_x, buf, bpp);
00151
00152
00153 bstart_x = center.x + lenght/2 + 1;
00154 bend_x = bstart_x + (blenght - lenght/2);
00155 Darken(bstart_x, bend_x, buf, bpp);
00156
00157 buf += line_size;
00158 y++;
00159 }
00160 }
00161
00162 void TileItem_AlphaSoftware::MergeSprite(const Point2i &position, Surface& spr)
00163 {
00164 need_check_empty = true;
00165 int starting_x = position.x >= 0 ? position.x : 0;
00166 int starting_y = position.y >= 0 ? position.y : 0;
00167 int ending_x = position.x+spr.GetWidth() <= m_surface.GetWidth() ? position.x+spr.GetWidth() : m_surface.GetWidth();
00168 int ending_y = position.y+spr.GetHeight() <= m_surface.GetHeight() ? position.y+spr.GetHeight() : m_surface.GetHeight();
00169 unsigned char r,g,b,a,p_r,p_g,p_b,p_a;
00170 unsigned char* spr_buf = spr.GetPixels();
00171 unsigned char* tile_buf = m_surface.GetPixels();
00172 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
00173 int r_offset = 0;
00174 int g_offset = 1;
00175 int b_offset = 2;
00176 int a_offset = 3;
00177 #else
00178 int r_offset = 3;
00179 int g_offset = 2;
00180 int b_offset = 1;
00181 int a_offset = 0;
00182 #endif
00183
00184
00185 spr_buf++;
00186
00187 for( int py = starting_y ; py < ending_y ; py++) {
00188 for( int px = starting_x ; px < ending_x ; px++) {
00189 a = *(spr_buf+((py-position.y)*spr.GetPitch()) + ((px-position.x) * 4 + a_offset));
00190 p_a = *(tile_buf + py*m_surface.GetPitch() + (px * 4) + a_offset);
00191 if (p_a > 0) {
00192 p_r = *(tile_buf + py*m_surface.GetPitch() + (px * 4) + r_offset);
00193 p_g = *(tile_buf + py*m_surface.GetPitch() + (px * 4) + g_offset);
00194 p_b = *(tile_buf + py*m_surface.GetPitch() + (px * 4) + b_offset);
00195 } else {
00196 p_r = p_g = p_b = 255;
00197 }
00198 if (a == SDL_ALPHA_OPAQUE || (p_a == 0 && a > 0)) {
00199 r = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + r_offset);
00200 g = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + g_offset);
00201 b = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + b_offset);
00202 *(tile_buf + py*m_surface.GetPitch() + (px * 4) + r_offset) = r;
00203 *(tile_buf + py*m_surface.GetPitch() + (px * 4) + g_offset) = g;
00204 *(tile_buf + py*m_surface.GetPitch() + (px * 4) + b_offset) = b;
00205 *(tile_buf + py*m_surface.GetPitch() + (px * 4) + a_offset) = a;
00206 } else if (a > 0) {
00207 r = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + r_offset);
00208 g = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + g_offset);
00209 b = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + b_offset);
00210 *(tile_buf + py*m_surface.GetPitch() + (px * 4) + r_offset) = (r * a + p_r * p_a) / (a + p_a);
00211 *(tile_buf + py*m_surface.GetPitch() + (px * 4) + g_offset) = (g * a + p_g * p_a) / (a + p_a);
00212 *(tile_buf + py*m_surface.GetPitch() + (px * 4) + b_offset) = (b * a + p_b * p_a) / (a + p_a);
00213 *(tile_buf + py*m_surface.GetPitch() + (px * 4) + a_offset) = (a > p_a ? a : p_a);
00214 }
00215 }
00216 }
00217 }
00218
00219 void TileItem_AlphaSoftware::Empty(const int start_x, const int end_x, unsigned char* buf, const int bpp)
00220 {
00221 if( start_x < CELL_SIZE.x && end_x >= 0)
00222 {
00223
00224 int tile_start_x = (start_x < 0) ? 0 : (start_x >= CELL_SIZE.x) ? CELL_SIZE.x - 1 : start_x;
00225 assert( tile_start_x >= 0 && tile_start_x < CELL_SIZE.x);
00226 int tile_lenght = (end_x >= CELL_SIZE.x) ? CELL_SIZE.x - tile_start_x : end_x - tile_start_x + 1;
00227 assert( tile_lenght > 0);
00228 assert( tile_start_x + tile_lenght <= CELL_SIZE.x);
00229
00230 assert(buf + tile_start_x * bpp + bpp * (tile_lenght-1) < m_surface.GetPixels() + CELL_SIZE.x * CELL_SIZE.y * bpp);
00231 memset(buf + tile_start_x * bpp, 0 , bpp * tile_lenght);
00232
00233
00234
00235
00236
00237 }
00238 }
00239
00240 void TileItem_AlphaSoftware::Darken(const int start_x, const int end_x, unsigned char* buf, const int bpp)
00241 {
00242 if( start_x < CELL_SIZE.x && end_x >= 0)
00243 {
00244
00245 int tile_start_x = (start_x < 0) ? 0 : (start_x >= CELL_SIZE.x) ? CELL_SIZE.x - 1 : start_x;
00246 assert( tile_start_x >= 0 && tile_start_x < CELL_SIZE.x);
00247 int tile_lenght = (end_x >= CELL_SIZE.x) ? CELL_SIZE.x - tile_start_x : end_x - tile_start_x + 1;
00248 assert( tile_lenght > 0);
00249 assert( tile_start_x + tile_lenght <= CELL_SIZE.x);
00250
00251 buf += tile_start_x * bpp;
00252 while(tile_lenght--)
00253 {
00254 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
00255 *(buf++) /= 2;
00256 *(buf++) /= 2;
00257 *(buf++) /= 2;
00258 buf++;
00259 #else
00260 buf++;
00261 *(buf++) /= 2;
00262 *(buf++) /= 2;
00263 *(buf++) /= 2;
00264 #endif
00265 }
00266 }
00267 }
00268
00269 Surface TileItem_AlphaSoftware::GetSurface(){
00270 return m_surface;
00271 }
00272
00273 #ifdef DBG_TILE
00274 void TileItem_AlphaSoftware::FillWithRGB(Uint8 r, Uint8 g, Uint8 b)
00275 {
00276 int x=0, y=0;
00277 while(y < CELL_SIZE.y)
00278 {
00279 Uint32 pixel = *(Uint32 *)(m_surface.GetPixels() + y*m_surface.GetPitch() + x*m_surface.GetBytesPerPixel());
00280 Uint8 tmp,a;
00281 m_surface.GetRGBA(pixel, tmp, tmp, tmp, a);
00282 if(a != SDL_ALPHA_TRANSPARENT)
00283 {
00284 Uint32 col = m_surface.MapRGBA(r, g, b, a);
00285 m_surface.PutPixel(x, y, col);
00286 }
00287 x++;
00288 if(x == CELL_SIZE.y)
00289 {
00290 x = 0;
00291 y++;
00292 }
00293 }
00294 }
00295 #endif
00296
00297 void TileItem_AlphaSoftware::CheckEmpty()
00298 {
00299 assert(need_check_empty);
00300 unsigned char alpha;
00301 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
00302 alpha = last_filled_pixel[3];
00303 #else
00304 alpha = last_filled_pixel[0];
00305 #endif
00306
00307 if(alpha == SDL_ALPHA_TRANSPARENT)
00308 {
00309 last_filled_pixel += 4;
00310 if( last_filled_pixel >= m_surface.GetPixels() + (m_surface.GetPitch() * CELL_SIZE.y))
00311 {
00312 need_delete = true;
00313 need_check_empty = false;
00314 }
00315 }
00316 else
00317 {
00318 need_check_empty = false;
00319 }
00320 }