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 | } |