Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 1 | /* |
| 2 | * Portions of this file are copyright Rebirth contributors and licensed as |
||
| 3 | * described in COPYING.txt. |
||
| 4 | * Portions of this file are copyright Parallax Software and licensed |
||
| 5 | * according to the Parallax license below. |
||
| 6 | * See COPYING.txt for license details. |
||
| 7 | |||
| 8 | THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX |
||
| 9 | SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO |
||
| 10 | END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A |
||
| 11 | ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS |
||
| 12 | IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS |
||
| 13 | SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE |
||
| 14 | FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE |
||
| 15 | CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS |
||
| 16 | AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. |
||
| 17 | COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. |
||
| 18 | */ |
||
| 19 | |||
| 20 | #include <stdlib.h> |
||
| 21 | #include "rle.h" |
||
| 22 | #include "compiler-range_for.h" |
||
| 23 | #include "d_range.h" |
||
| 24 | #include <array> |
||
| 25 | |||
| 26 | namespace dcx { |
||
| 27 | |||
| 28 | // John's new stuff below here.... |
||
| 29 | |||
| 30 | static int scale_error_term; |
||
| 31 | static int scale_initial_pixel_count; |
||
| 32 | static int scale_adj_up; |
||
| 33 | static int scale_adj_down; |
||
| 34 | static int scale_final_pixel_count; |
||
| 35 | static int scale_ydelta_minus_1; |
||
| 36 | static int scale_whole_step; |
||
| 37 | |||
| 38 | static void rls_stretch_scanline_setup( int XDelta, int YDelta ); |
||
| 39 | static void rls_stretch_scanline(const uint8_t *, uint8_t *); |
||
| 40 | |||
| 41 | static void decode_row(const grs_bitmap &bmp, std::array<color_palette_index, 640> &scale_rle_data, const uint_fast32_t y) |
||
| 42 | { |
||
| 43 | int offset=4+bmp.bm_h; |
||
| 44 | |||
| 45 | range_for (const uint_fast32_t i, xrange(y)) |
||
| 46 | offset += bmp.bm_data[4+i]; |
||
| 47 | gr_rle_decode(&bmp.bm_data[offset], scale_rle_data.data(), rle_end(bmp, scale_rle_data)); |
||
| 48 | } |
||
| 49 | |||
| 50 | static void scale_up_bitmap(const grs_bitmap &source_bmp, grs_bitmap &dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0, fix u1, fix v1, int orientation ) |
||
| 51 | { |
||
| 52 | fix dv, v; |
||
| 53 | if (orientation & 1) { |
||
| 54 | int t; |
||
| 55 | t = u0; u0 = u1; u1 = t; |
||
| 56 | } |
||
| 57 | |||
| 58 | if (orientation & 2) { |
||
| 59 | int t; |
||
| 60 | t = v0; v0 = v1; v1 = t; |
||
| 61 | if (v1 < v0) |
||
| 62 | v0--; |
||
| 63 | } |
||
| 64 | |||
| 65 | v = v0; |
||
| 66 | |||
| 67 | dv = (v1-v0) / (y1-y0); |
||
| 68 | |||
| 69 | rls_stretch_scanline_setup(x1 - x0, f2i(u1) - f2i(u0)); |
||
| 70 | if ( scale_ydelta_minus_1 < 1 ) return; |
||
| 71 | |||
| 72 | v = v0; |
||
| 73 | |||
| 74 | for (int y=y0; y<=y1; y++ ) { |
||
| 75 | rls_stretch_scanline(&source_bmp.get_bitmap_data()[source_bmp.bm_rowsize*f2i(v)+f2i(u0)], &dest_bmp.get_bitmap_data()[dest_bmp.bm_rowsize*y+x0]); |
||
| 76 | v += dv; |
||
| 77 | } |
||
| 78 | } |
||
| 79 | |||
| 80 | static void scale_up_bitmap_rle(const grs_bitmap &source_bmp, grs_bitmap &dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0, fix u1, fix v1, int orientation ) |
||
| 81 | { |
||
| 82 | fix dv, v; |
||
| 83 | int last_row = -1; |
||
| 84 | |||
| 85 | if (orientation & 1) { |
||
| 86 | int t; |
||
| 87 | t = u0; u0 = u1; u1 = t; |
||
| 88 | } |
||
| 89 | |||
| 90 | if (orientation & 2) { |
||
| 91 | int t; |
||
| 92 | t = v0; v0 = v1; v1 = t; |
||
| 93 | if (v1 < v0) |
||
| 94 | v0--; |
||
| 95 | } |
||
| 96 | |||
| 97 | dv = (v1-v0) / (y1-y0); |
||
| 98 | |||
| 99 | rls_stretch_scanline_setup(x1 - x0, f2i(u1) - f2i(u0)); |
||
| 100 | if ( scale_ydelta_minus_1 < 1 ) return; |
||
| 101 | |||
| 102 | v = v0; |
||
| 103 | |||
| 104 | std::array<color_palette_index, 640> scale_rle_data; |
||
| 105 | for (int y=y0; y<=y1; y++ ) { |
||
| 106 | if ( f2i(v) != last_row ) { |
||
| 107 | last_row = f2i(v); |
||
| 108 | decode_row(source_bmp, scale_rle_data, last_row ); |
||
| 109 | } |
||
| 110 | rls_stretch_scanline(&scale_rle_data[f2i(u0)], &dest_bmp.get_bitmap_data()[dest_bmp.bm_rowsize*y+x0]); |
||
| 111 | v += dv; |
||
| 112 | } |
||
| 113 | } |
||
| 114 | |||
| 115 | static void rls_stretch_scanline_setup( int XDelta, int YDelta ) |
||
| 116 | { |
||
| 117 | scale_ydelta_minus_1 = YDelta - 1; |
||
| 118 | |||
| 119 | /* X major line */ |
||
| 120 | /* Minimum # of pixels in a run in this line */ |
||
| 121 | scale_whole_step = XDelta / YDelta; |
||
| 122 | |||
| 123 | /* Error term adjust each time Y steps by 1; used to tell when one |
||
| 124 | extra pixel should be drawn as part of a run, to account for |
||
| 125 | fractional steps along the X axis per 1-pixel steps along Y */ |
||
| 126 | scale_adj_up = (XDelta % YDelta) * 2; |
||
| 127 | |||
| 128 | /* Error term adjust when the error term turns over, used to factor |
||
| 129 | out the X step made at that time */ |
||
| 130 | scale_adj_down = YDelta * 2; |
||
| 131 | |||
| 132 | /* Initial error term; reflects an initial step of 0.5 along the Y |
||
| 133 | axis */ |
||
| 134 | scale_error_term = (XDelta % YDelta) - (YDelta * 2); |
||
| 135 | |||
| 136 | /* The initial and last runs are partial, because Y advances only 0.5 |
||
| 137 | for these runs, rather than 1. Divide one full run, plus the |
||
| 138 | initial pixel, between the initial and last runs */ |
||
| 139 | scale_initial_pixel_count = (scale_whole_step / 2) + 1; |
||
| 140 | scale_final_pixel_count = scale_initial_pixel_count; |
||
| 141 | |||
| 142 | /* If the basic run length is even and there's no fractional |
||
| 143 | advance, we have one pixel that could go to either the initial |
||
| 144 | or last partial run, which we'll arbitrarily allocate to the |
||
| 145 | last run */ |
||
| 146 | if ((scale_adj_up == 0) && ((scale_whole_step & 0x01) == 0)) |
||
| 147 | { |
||
| 148 | scale_initial_pixel_count--; |
||
| 149 | } |
||
| 150 | /* If there're an odd number of pixels per run, we have 1 pixel that can't |
||
| 151 | be allocated to either the initial or last partial run, so we'll add 0.5 |
||
| 152 | to error term so this pixel will be handled by the normal full-run loop */ |
||
| 153 | if ((scale_whole_step & 0x01) != 0) |
||
| 154 | { |
||
| 155 | scale_error_term += YDelta; |
||
| 156 | } |
||
| 157 | |||
| 158 | } |
||
| 159 | |||
| 160 | static void rls_stretch_scanline(const color_palette_index *scale_source_ptr, color_palette_index *scale_dest_ptr) |
||
| 161 | { |
||
| 162 | int ErrorTerm, initial_count, final_count; |
||
| 163 | |||
| 164 | // Draw the first, partial run of pixels |
||
| 165 | |||
| 166 | auto src_ptr = scale_source_ptr; |
||
| 167 | auto dest_ptr = scale_dest_ptr; |
||
| 168 | ErrorTerm = scale_error_term; |
||
| 169 | initial_count = scale_initial_pixel_count; |
||
| 170 | final_count = scale_final_pixel_count; |
||
| 171 | |||
| 172 | const auto process_line = [&dest_ptr, &src_ptr](const unsigned len) |
||
| 173 | { |
||
| 174 | const auto c = *src_ptr++; |
||
| 175 | if (c != TRANSPARENCY_COLOR) |
||
| 176 | std::fill_n(dest_ptr, len, c); |
||
| 177 | dest_ptr += len; |
||
| 178 | }; |
||
| 179 | process_line(initial_count); |
||
| 180 | |||
| 181 | // Draw all full runs |
||
| 182 | |||
| 183 | for (int j=0; j<scale_ydelta_minus_1; j++) { |
||
| 184 | unsigned len = scale_whole_step; // run is at least this long |
||
| 185 | |||
| 186 | // Advance the error term and add an extra pixel if the error term so indicates |
||
| 187 | if ((ErrorTerm += scale_adj_up) > 0) { |
||
| 188 | len++; |
||
| 189 | ErrorTerm -= scale_adj_down; // reset the error term |
||
| 190 | } |
||
| 191 | |||
| 192 | // Draw this run o' pixels |
||
| 193 | process_line(len); |
||
| 194 | } |
||
| 195 | |||
| 196 | // Draw the final run of pixels |
||
| 197 | process_line(final_count); |
||
| 198 | } |
||
| 199 | |||
| 200 | // old stuff here... |
||
| 201 | |||
| 202 | static void scale_bitmap_c(const grs_bitmap &source_bmp, grs_bitmap &dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0, fix u1, fix v1, int orientation ) |
||
| 203 | { |
||
| 204 | fix u, v, du, dv; |
||
| 205 | |||
| 206 | du = (u1-u0) / (x1-x0); |
||
| 207 | dv = (v1-v0) / (y1-y0); |
||
| 208 | |||
| 209 | if (orientation & 1) { |
||
| 210 | u0 = u1; |
||
| 211 | du = -du; |
||
| 212 | } |
||
| 213 | |||
| 214 | if (orientation & 2) { |
||
| 215 | v0 = v1; |
||
| 216 | dv = -dv; |
||
| 217 | if (dv < 0) |
||
| 218 | v0--; |
||
| 219 | } |
||
| 220 | |||
| 221 | v = v0; |
||
| 222 | |||
| 223 | for (int y=y0; y<=y1; y++ ) { |
||
| 224 | auto sbits = &source_bmp.get_bitmap_data()[source_bmp.bm_rowsize*f2i(v)]; |
||
| 225 | auto dbits = &dest_bmp.get_bitmap_data()[dest_bmp.bm_rowsize*y+x0]; |
||
| 226 | u = u0; |
||
| 227 | v += dv; |
||
| 228 | for (int x=x0; x<=x1; x++ ) { |
||
| 229 | auto c = sbits[u >> 16]; |
||
| 230 | if (c != TRANSPARENCY_COLOR) |
||
| 231 | *dbits = c; |
||
| 232 | dbits++; |
||
| 233 | u += du; |
||
| 234 | } |
||
| 235 | } |
||
| 236 | } |
||
| 237 | |||
| 238 | static void scale_row_transparent(const std::array<ubyte, 640> &sbits, color_palette_index *dbits, int width, fix u, fix du ) |
||
| 239 | { |
||
| 240 | const auto dbits_end = &dbits[width-1]; |
||
| 241 | |||
| 242 | if ( du < F1_0 ) { |
||
| 243 | // Scaling up. |
||
| 244 | fix next_u; |
||
| 245 | int next_u_int; |
||
| 246 | |||
| 247 | next_u_int = f2i(u)+1; |
||
| 248 | auto c = sbits[next_u_int]; |
||
| 249 | next_u = i2f(next_u_int); |
||
| 250 | if ( c != TRANSPARENCY_COLOR ) goto NonTransparent; |
||
| 251 | |||
| 252 | Transparent: |
||
| 253 | while (1) { |
||
| 254 | dbits++; |
||
| 255 | if ( dbits > dbits_end ) return; |
||
| 256 | u += du; |
||
| 257 | if ( u > next_u ) { |
||
| 258 | next_u_int = f2i(u)+1; |
||
| 259 | c = sbits[ next_u_int ]; |
||
| 260 | next_u = i2f(next_u_int); |
||
| 261 | if ( c != TRANSPARENCY_COLOR ) goto NonTransparent; |
||
| 262 | } |
||
| 263 | } |
||
| 264 | return; |
||
| 265 | |||
| 266 | NonTransparent: |
||
| 267 | while (1) { |
||
| 268 | *dbits++ = c; |
||
| 269 | if ( dbits > dbits_end ) return; |
||
| 270 | u += du; |
||
| 271 | if ( u > next_u ) { |
||
| 272 | next_u_int = f2i(u)+1; |
||
| 273 | c = sbits[ next_u_int ]; |
||
| 274 | next_u = i2f(next_u_int); |
||
| 275 | if ( c == TRANSPARENCY_COLOR ) goto Transparent; |
||
| 276 | } |
||
| 277 | } |
||
| 278 | return; |
||
| 279 | |||
| 280 | |||
| 281 | |||
| 282 | } else { |
||
| 283 | for ( int i=0; i<width; i++ ) { |
||
| 284 | const auto c = sbits[ f2i(u) ]; |
||
| 285 | |||
| 286 | if ( c != TRANSPARENCY_COLOR ) |
||
| 287 | *dbits = c; |
||
| 288 | |||
| 289 | dbits++; |
||
| 290 | u += du; |
||
| 291 | } |
||
| 292 | } |
||
| 293 | } |
||
| 294 | |||
| 295 | static void scale_bitmap_c_rle(const grs_bitmap &source_bmp, grs_bitmap &dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0, fix u1, fix v1, int orientation ) |
||
| 296 | { |
||
| 297 | fix du, dv, v; |
||
| 298 | int last_row=-1; |
||
| 299 | |||
| 300 | // Rotation doesn't work because explosions are not square! |
||
| 301 | // -- if (orientation & 4) { |
||
| 302 | // -- int t; |
||
| 303 | // -- t = u0; u0 = v0; v0 = t; |
||
| 304 | // -- t = u1; u1 = v1; v1 = t; |
||
| 305 | // -- } |
||
| 306 | |||
| 307 | du = (u1-u0) / (x1-x0); |
||
| 308 | dv = (v1-v0) / (y1-y0); |
||
| 309 | |||
| 310 | if (orientation & 1) { |
||
| 311 | u0 = u1; |
||
| 312 | du = -du; |
||
| 313 | } |
||
| 314 | |||
| 315 | if (orientation & 2) { |
||
| 316 | v0 = v1; |
||
| 317 | dv = -dv; |
||
| 318 | if (dv < 0) |
||
| 319 | v0--; |
||
| 320 | } |
||
| 321 | |||
| 322 | v = v0; |
||
| 323 | |||
| 324 | if (v<0) { //was: Assert(v >= 0); |
||
| 325 | //Int3(); //this should be checked in higher-level routine |
||
| 326 | return; |
||
| 327 | } |
||
| 328 | |||
| 329 | std::array<ubyte, 640> scale_rle_data; |
||
| 330 | for (int y=y0; y<=y1; y++ ) { |
||
| 331 | if ( f2i(v) != last_row ) { |
||
| 332 | last_row = f2i(v); |
||
| 333 | decode_row(source_bmp, scale_rle_data, last_row ); |
||
| 334 | } |
||
| 335 | scale_row_transparent( scale_rle_data, &dest_bmp.get_bitmap_data()[dest_bmp.bm_rowsize*y+x0], x1-x0+1, u0, du ); |
||
| 336 | v += dv; |
||
| 337 | } |
||
| 338 | } |
||
| 339 | |||
| 340 | #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (fixmuldiv((x)-(x0),(y1)-(y0),(x1)-(x0))+(y0)) |
||
| 341 | |||
| 342 | // Scales bitmap, bp, into vertbuf[0] to vertbuf[1] |
||
| 343 | void scale_bitmap(const grs_bitmap &bp, const std::array<grs_point, 3> &vertbuf, int orientation, grs_bitmap &dbp) |
||
| 344 | { |
||
| 345 | fix x0, y0, x1, y1; |
||
| 346 | fix u0, v0, u1, v1; |
||
| 347 | fix clipped_x0, clipped_y0, clipped_x1, clipped_y1; |
||
| 348 | fix clipped_u0, clipped_v0, clipped_u1, clipped_v1; |
||
| 349 | fix xmin, xmax, ymin, ymax; |
||
| 350 | int dx0, dy0, dx1, dy1; |
||
| 351 | int dtemp; |
||
| 352 | // Set initial variables.... |
||
| 353 | |||
| 354 | x0 = vertbuf[0].x; y0 = vertbuf[0].y; |
||
| 355 | x1 = vertbuf[2].x; y1 = vertbuf[2].y; |
||
| 356 | |||
| 357 | xmin = 0; ymin = 0; |
||
| 358 | xmax = i2f(dbp.bm_w)-fl2f(.5); ymax = i2f(dbp.bm_h)-fl2f(.5); |
||
| 359 | |||
| 360 | u0 = i2f(0); v0 = i2f(0); |
||
| 361 | u1 = i2f(bp.bm_w-1); v1 = i2f(bp.bm_h-1); |
||
| 362 | |||
| 363 | // Check for obviously offscreen bitmaps... |
||
| 364 | if ( (y1<=y0) || (x1<=x0) ) return; |
||
| 365 | if ( (x1<0 ) || (x0>=xmax) ) return; |
||
| 366 | if ( (y1<0 ) || (y0>=ymax) ) return; |
||
| 367 | |||
| 368 | clipped_u0 = u0; clipped_v0 = v0; |
||
| 369 | clipped_u1 = u1; clipped_v1 = v1; |
||
| 370 | |||
| 371 | clipped_x0 = x0; clipped_y0 = y0; |
||
| 372 | clipped_x1 = x1; clipped_y1 = y1; |
||
| 373 | |||
| 374 | // Clip the left, moving u0 right as necessary |
||
| 375 | if ( x0 < xmin ) { |
||
| 376 | clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1); |
||
| 377 | clipped_x0 = xmin; |
||
| 378 | } |
||
| 379 | |||
| 380 | // Clip the right, moving u1 left as necessary |
||
| 381 | if ( x1 > xmax ) { |
||
| 382 | clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1); |
||
| 383 | clipped_x1 = xmax; |
||
| 384 | } |
||
| 385 | |||
| 386 | // Clip the top, moving v0 down as necessary |
||
| 387 | if ( y0 < ymin ) { |
||
| 388 | clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1); |
||
| 389 | clipped_y0 = ymin; |
||
| 390 | } |
||
| 391 | |||
| 392 | // Clip the bottom, moving v1 up as necessary |
||
| 393 | if ( y1 > ymax ) { |
||
| 394 | clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1); |
||
| 395 | clipped_y1 = ymax; |
||
| 396 | } |
||
| 397 | |||
| 398 | dx0 = f2i(clipped_x0); dx1 = f2i(clipped_x1); |
||
| 399 | dy0 = f2i(clipped_y0); dy1 = f2i(clipped_y1); |
||
| 400 | |||
| 401 | if (dx1<=dx0) return; |
||
| 402 | if (dy1<=dy0) return; |
||
| 403 | |||
| 404 | dtemp = f2i(clipped_u1)-f2i(clipped_u0); |
||
| 405 | |||
| 406 | if (bp.get_flag_mask(BM_FLAG_RLE)) |
||
| 407 | { |
||
| 408 | if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) ) |
||
| 409 | scale_up_bitmap_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1, orientation ); |
||
| 410 | else |
||
| 411 | scale_bitmap_c_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1, orientation ); |
||
| 412 | } else { |
||
| 413 | if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) ) |
||
| 414 | scale_up_bitmap(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1, orientation ); |
||
| 415 | else |
||
| 416 | scale_bitmap_c(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1, orientation ); |
||
| 417 | } |
||
| 418 | } |
||
| 419 | |||
| 420 | } |