|
Atrinik Client 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00045 #include <global.h> 00046 00079 static int std_tile_half_len[] = 00080 { 00081 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 00082 10, 10, 11, 11, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 00083 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0 00084 }; 00085 00087 typedef struct line_and_slope 00088 { 00090 int sx; 00091 00093 int sy; 00094 00096 int end_x; 00097 00099 int end_y; 00100 00105 float slope; 00106 } line_and_slope; 00107 00117 static void determine_line(line_and_slope *dest, int sx, int sy, int ex, int ey) 00118 { 00119 float y_diff, x_diff, slope; 00120 00121 if (sy > ey) 00122 { 00123 y_diff = sy - ey; 00124 } 00125 else 00126 { 00127 y_diff = ey - sy; 00128 } 00129 00130 if (sx > ex) 00131 { 00132 x_diff = sx - ex; 00133 } 00134 else 00135 { 00136 x_diff = ex - sx; 00137 } 00138 00139 if (x_diff == 0) 00140 { 00141 slope = 0.0; 00142 } 00143 else 00144 { 00145 slope = y_diff / x_diff; 00146 } 00147 00148 dest->sx = sx; 00149 dest->sy = sy; 00150 dest->end_x = ex; 00151 dest->end_y = ey; 00152 dest->slope = slope; 00153 } 00154 00157 int add_color_to_surface(SDL_Surface *dest, Uint8 red, Uint8 green, Uint8 blue) 00158 { 00159 int i; 00160 Uint8 ncol = dest->format->palette->ncolors; 00161 SDL_Color colors[256]; 00162 00163 for (i = 0; i < ncol; i++) 00164 { 00165 colors[i].r = dest->format->palette->colors[i].r; 00166 colors[i].g = dest->format->palette->colors[i].g; 00167 colors[i].b = dest->format->palette->colors[i].b; 00168 } 00169 00170 colors[ncol].r = red; 00171 colors[ncol].g = green; 00172 colors[ncol].b = blue; 00173 ncol++; 00174 00175 SDL_SetColors(dest, colors, 0, ncol); 00176 dest->format->palette->ncolors = ncol; 00177 00178 return 0; 00179 } 00180 00193 int copy_pixel_to_pixel(SDL_Surface *src, SDL_Surface *dest, int x, int y, int x2, int y2, float brightness) 00194 { 00195 Uint32 color; 00196 Uint8 red, green, blue, alpha, alpha_2; 00197 Uint8 red_2, green_2, blue_2; 00198 Uint16 n; 00199 00200 if (x < 0 || y < 0 || x2 < 0 || y2 < 0) 00201 { 00202 return 0; 00203 } 00204 00205 if (x >= src->w || x2 >= dest->w || y >= src->h || y2 >= dest->h) 00206 { 00207 return 0; 00208 } 00209 00210 color = getpixel(src, x, y); 00211 00212 /* No need to copy transparent pixels */ 00213 if (src->format->BitsPerPixel == 8 && (color == src->format->colorkey)) 00214 { 00215 return 0; 00216 } 00217 00218 SDL_GetRGBA(color, src->format, &red, &green, &blue, &alpha); 00219 00220 if (alpha == 0) 00221 { 00222 return 0; 00223 } 00224 00225 /* We must clamp to 255 since it is allowable for brightness to exceed 1.0 */ 00226 n = (Uint16) red * brightness; 00227 red = (n <= 255) ? n : 255; 00228 n = (Uint16) green * brightness; 00229 green = (n <= 255) ? n : 255; 00230 n = (Uint16) blue * brightness; 00231 blue = (n <= 255) ? n : 255; 00232 00233 color = SDL_MapRGBA(dest->format, red, green, blue, alpha); 00234 00235 if (color == dest->format->colorkey) 00236 { 00237 blue += 256 >> (8 - dest->format->Bloss); 00238 color = SDL_MapRGBA(dest->format, red, green, blue, alpha); 00239 } 00240 00241 if (dest->format->BitsPerPixel == 8) 00242 { 00243 SDL_GetRGBA(color, dest->format, &red_2, &green_2, &blue_2, &alpha_2); 00244 00245 if (red != red_2 || green != green_2 || blue != blue_2 || alpha != alpha_2) 00246 { 00247 add_color_to_surface(dest, red, green, blue); 00248 color = SDL_MapRGBA(dest->format, red, green, blue, alpha); 00249 } 00250 } 00251 00252 putpixel(dest, x2, y2, color); 00253 return 0; 00254 } 00255 00277 int copy_vertical_line(SDL_Surface *src, SDL_Surface *dest, int src_x, int src_sy, int src_ey, int dest_x, int dest_sy, int dest_ey, float brightness, int extra) 00278 { 00279 int src_h, dest_h, y; 00280 float ratio; 00281 00282 SDL_LockSurface(src); 00283 SDL_LockSurface(dest); 00284 00285 if (src_sy > src_ey) 00286 { 00287 int tmp = src_sy; 00288 00289 src_sy = src_ey; 00290 src_ey = tmp; 00291 } 00292 00293 if (dest_sy > dest_ey) 00294 { 00295 int tmp = dest_sy; 00296 00297 dest_sy = dest_ey; 00298 dest_ey = tmp; 00299 } 00300 00301 src_h = src_ey - src_sy; 00302 dest_h = dest_ey - dest_sy; 00303 00304 /* Special cases */ 00305 if (dest_h == 0) 00306 { 00307 if (src_h == 0) 00308 { 00309 copy_pixel_to_pixel(src, dest, src_x, src_sy, dest_x, dest_sy, brightness); 00310 00311 SDL_UnlockSurface(src); 00312 SDL_UnlockSurface(dest); 00313 return 0; 00314 } 00315 else 00316 { 00317 copy_pixel_to_pixel(src, dest, src_x, (src_ey - src_sy) / 2, dest_x, dest_sy, brightness); 00318 00319 SDL_UnlockSurface(src); 00320 SDL_UnlockSurface(dest); 00321 return 0; 00322 } 00323 } 00324 00325 if (src_h == 0) 00326 { 00327 Uint32 color = getpixel(src, src_x, src_sy); 00328 00329 for (y = dest_sy; y <= dest_ey; y++) 00330 { 00331 putpixel(dest, dest_x, y, color); 00332 } 00333 00334 return 0; 00335 } 00336 00337 /* The stretching */ 00338 ratio = (float) src_h / (float) dest_h; 00339 00340 for (y = 0; y <= dest_h; y++) 00341 { 00342 int go_y = dest_sy + y; 00343 int get_y = src_sy + (y * ratio); 00344 00345 copy_pixel_to_pixel(src, dest, src_x, get_y, dest_x, go_y, brightness); 00346 } 00347 00348 if (extra) 00349 { 00350 if (dest_ey + 1 < dest->h) 00351 { 00352 copy_pixel_to_pixel(src, dest, src_x, src_ey, dest_x, dest_ey + 1, brightness); 00353 } 00354 } 00355 00356 SDL_UnlockSurface(src); 00357 SDL_UnlockSurface(dest); 00358 return 0; 00359 } 00360 00387 SDL_Surface *tile_stretch(SDL_Surface *src, int n, int e, int s, int w) 00388 { 00389 SDL_Surface *destination, *tmp; 00390 float e_dark = 1.0, w_dark = 1.0; 00391 /* If set, copy_vertical_line will attempt to extend the line further 00392 * by 1 pixel (no idea why this is named "flat") */ 00393 int flat; 00394 int sx, sy, ex, ey; 00395 int ln_num; 00396 int dest_sx, dest_sy, dest_ex, dest_ey; 00397 float dest_slope; 00398 int dest_sy_2, dest_ey_2; 00399 float dest_slope_2; 00400 int dest_x_inc, dest_y_inc; 00401 float kicker, kicker_2; 00402 int dest_y_inc_2; 00403 int x, y, y2; 00404 int at_least_one; 00405 int src_len; 00406 Uint32 color; 00407 Uint8 red, green, blue, alpha; 00408 /* Only index numbers 0-3 are actually used */ 00409 line_and_slope dest_lines[10]; 00410 00411 /* Initialisation and housekeeping */ 00412 SDL_LockSurface(src); 00413 00414 tmp = SDL_CreateRGBSurface(src->flags, src->w, src->h + n, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask); 00415 00416 destination = SDL_DisplayFormatAlpha(tmp); 00417 SDL_FreeSurface(tmp); 00418 SDL_LockSurface(destination); 00419 00420 color = getpixel(src, 0, 0); 00421 00422 SDL_GetRGBA(color, src->format, &red, &green, &blue, &alpha); 00423 00424 if (src->format->BitsPerPixel == 8) 00425 { 00426 add_color_to_surface(destination, red, green, blue); 00427 } 00428 00429 /* We fill with black and full trans... */ 00430 color = SDL_MapRGBA(destination->format, 0, 0, 0, 0); 00431 SDL_FillRect( destination, NULL, color); 00432 00433 if (src->format->BitsPerPixel == 8) 00434 { 00435 SDL_SetColorKey(destination, SDL_SRCCOLORKEY, color); 00436 } 00437 00438 /* If the target is the same size we don't want copy_vertical_line() 00439 * to try to extent the line by 1 pixel */ 00440 if (n == 0 && e == 0 && w == 0 && s == 0) 00441 { 00442 flat = 0; 00443 } 00444 else 00445 { 00446 flat = 1; 00447 } 00448 00449 /* Calculate the darkness (contrast) of one or both sides */ 00450 if (w > e) 00451 { 00452 w_dark = 1.0 - ((w - e) / 25.0); 00453 00454 if (n > 0 || s > 0) 00455 { 00456 e_dark = w_dark; 00457 } 00458 } 00459 00460 if (e > w) 00461 { 00462 e_dark = 1.0 + ((e - w) / 25.0); 00463 00464 if (s > 0 || n > 0) 00465 { 00466 w_dark = e_dark; 00467 } 00468 } 00469 00470 /* Calculate the information about the lines which will form the 00471 * edge of the stretched tile (see the comments above 00472 * std_tile_half_len for a picture). 00473 * 00474 * In the isometric view, closer objects are displayed lower down 00475 * on the VDU (smaller y co-ordinate) and further objects are 00476 * displayed higher up (larger y co-ordinate). 00477 * 00478 * The SW corner moves closer the more West the tile is stretched. 00479 * The NE corner moves closer the more East the tile is stretched. 00480 * Both the SW and NE corners move further away the more North the 00481 * tile is stretched. 00482 * Both the SE and NW corners move close the more South and further 00483 * away the more North the tile is stretched */ 00484 00485 /* 0: Southern edge: SW to SE corner */ 00486 sx = 2; 00487 sy = (10 - w) + n; 00488 ex = 22; 00489 ey = 0; 00490 determine_line(&dest_lines[0], sx, sy, ex, ey); 00491 /* 1: Western edge: SW to NW corner */ 00492 sx = 2; 00493 sy = (12 - w) + n; 00494 ex = 22; 00495 ey = 22 + n - s; 00496 determine_line(&dest_lines[1], sx, sy, ex, ey); 00497 /* 2: Eastern edge: NE to SE corner */ 00498 sx = 45; 00499 sy = (10 - e) + n; 00500 ex = 25; 00501 ey = 0; 00502 determine_line(&dest_lines[2], sx, sy, ex, ey); 00503 /* 3: Northern edge: NE to NW corner */ 00504 sx = 45; 00505 sy = (12 - e) + n; 00506 ex = 25; 00507 ey = 22 + n - s; 00508 determine_line(&dest_lines[3], sx, sy, ex, ey); 00509 00510 /* loop information: 00511 * effective loop control: 00512 * for (ln_num = 0; ln_num < 4; ln_num += 2) */ 00513 for (ln_num = 0; ln_num < 4; ln_num++) 00514 { 00515 /* see "effective loop control" */ 00516 if (ln_num == 1 || ln_num == 3) 00517 { 00518 continue; 00519 } 00520 00521 /* Extract the information for the first, i.e. bottom, line (S or E edge) */ 00522 dest_sx = dest_lines[ln_num].sx; 00523 dest_sy = dest_lines[ln_num].sy; 00524 dest_ex = dest_lines[ln_num].end_x; 00525 dest_ey = dest_lines[ln_num].end_y; 00526 dest_slope = dest_lines[ln_num].slope; 00527 00528 /* ln_num is always either 0 or 2 here */ 00529 if (ln_num == 0 || ln_num == 2) 00530 { 00531 /* Extract the information for the second, i.e. top, line (W or N edge) */ 00532 dest_sy_2 = dest_lines[ln_num + 1].sy; 00533 dest_ey_2 = dest_lines[ln_num + 1].end_y; 00534 dest_slope_2 = dest_lines[ln_num + 1].slope; 00535 } 00536 else 00537 { 00538 /* Dead code: information about the second line is the same as the first! */ 00539 dest_sy_2 = dest_lines[ln_num].sy; 00540 dest_ey_2 = dest_lines[ln_num].end_y; 00541 dest_slope_2 = dest_lines[ln_num].slope; 00542 } 00543 00544 /* Calculate the direction of the y co-ordinate */ 00545 if (dest_sy > dest_ey) 00546 { 00547 dest_y_inc = -1; 00548 } 00549 else 00550 { 00551 dest_y_inc = 1; 00552 } 00553 00554 /* Calculate the direction of the x co-ordinate */ 00555 if (dest_sx > dest_ex) 00556 { 00557 dest_x_inc = -1; 00558 } 00559 else 00560 { 00561 dest_x_inc = 1; 00562 } 00563 00564 /* Calculate the direction of the 2nd y co-ordinate */ 00565 if (dest_sy_2 > dest_ey_2) 00566 { 00567 dest_y_inc_2 = -1; 00568 } 00569 else 00570 { 00571 dest_y_inc_2 = 1; 00572 } 00573 00574 /* Initialise loop controls: "kicker" means the co-ordinate 00575 * crosses the line (another weird name) */ 00576 x = dest_sx; 00577 y = dest_sy; 00578 kicker = 0.0; 00579 y2 = dest_sy_2; 00580 kicker_2 = 0.0; 00581 /* Make sure at least one row of pixels is output (who chose that name?) */ 00582 at_least_one = 0; 00583 00584 /* Main inner loop to draw each vertical line in the stretched bitmap 00585 * loop information: 00586 * 00587 * horizontal (or vertical) edges are drawn with only one line of pixels (at_least_one) 00588 * 00589 * effective loop control when non-horizontal: 00590 * for (x1 = dest_sx; x1 != dest_ex; x1 += dest_x_inc) */ 00591 while (((dest_slope != 0.0) && (x != dest_ex) && (y != dest_ey)) || ((at_least_one == 0) && (dest_slope == 0.0))) 00592 { 00593 /* Exit the loop after the first iteration if the line is exactly horizontal (or vertical) */ 00594 at_least_one = 1; 00595 00596 if (kicker >= 1.0) 00597 { 00598 kicker = kicker - 1.0; 00599 y = y + dest_y_inc; 00600 } 00601 00602 if (kicker_2 >= 1.0) 00603 { 00604 kicker_2 = kicker_2 - 1.0; 00605 y2 = y2 + dest_y_inc_2; 00606 } 00607 00608 /* Choose y co-ordinates either side of the central horizontal */ 00609 src_len = std_tile_half_len[x]; 00610 00611 if (ln_num < 2) 00612 { 00613 copy_vertical_line(src, destination, x, 11 + src_len, 11 - src_len, x, y, y2, w_dark, flat); 00614 } 00615 else 00616 { 00617 copy_vertical_line(src, destination, x, 11 + src_len, 11 - src_len, x, y, y2, e_dark, flat); 00618 } 00619 00620 x = x + dest_x_inc; 00621 00622 kicker = kicker + dest_slope; 00623 kicker_2 = kicker_2 + dest_slope_2; 00624 } 00625 } 00626 00627 for (x = 22; x < 22 + 2; x++) 00628 { 00629 copy_vertical_line(src, destination, x, 0, 23, x, 0, 23 + n - s, w_dark, flat); 00630 } 00631 00632 for (x = 24; x < 24 + 2; x++) 00633 { 00634 copy_vertical_line(src, destination, x, 0, 23, x, 0, 23 + n - s, e_dark, flat); 00635 } 00636 00637 for (x = 0; x < 2; x++) 00638 { 00639 copy_pixel_to_pixel(src,destination, x, 11, x, 11 + n - w, w_dark); 00640 } 00641 00642 for (x = 46; x < 48; x++) 00643 { 00644 copy_pixel_to_pixel(src, destination, x, 11, x, 11 + n - e, e_dark); 00645 } 00646 00647 SDL_UnlockSurface(src); 00648 SDL_UnlockSurface(destination); 00649 return destination; 00650 }
1.7.4