Subversion Repositories Games.Descent

Rev

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
}