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