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