This commit was manufactured by cvs2svn to create tag 'd2x-0_1_2'.
[btb/d2x.git] / 2d / scale.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  * $Source: /cvs/cvsroot/d2x/2d/scale.c,v $
15  * $Revision: 1.2 $
16  * $Author: bradleyb $
17  * $Date: 2001-01-31 15:17:48 $
18  * 
19  * Routines for scaling a bitmap.
20  * 
21  * $Log: not supported by cvs2svn $
22  * Revision 1.1.1.1  2001/01/19 03:29:57  bradleyb
23  * Import of d2x-0.0.8
24  *
25  * Revision 1.1.1.1  1999/06/14 21:57:36  donut
26  * Import of d1x 1.37 source.
27  *
28  * Revision 1.12  1995/03/14  15:14:11  john
29  * Increased max scanline length to 640.
30  * ..
31  * 
32  * Revision 1.11  1994/11/27  12:56:39  matt
33  * Took out unneeded include of 3d.h
34  * 
35  * Revision 1.10  1994/11/18  22:50:25  john
36  * Changed shorts to ints in parameters.
37  * 
38  * Revision 1.9  1994/11/09  16:35:02  john
39  * First version with working RLE bitmaps.
40  * 
41  * Revision 1.8  1994/06/09  13:15:17  john
42  * *** empty log message ***
43  * 
44  * Revision 1.7  1994/06/07  11:47:02  john
45  * Added back in the fast code for scaling up bitmaps.
46  * 
47  * Revision 1.6  1994/02/18  15:32:36  john
48  * *** empty log message ***
49  * 
50  * Revision 1.5  1994/01/22  14:35:01  john
51  * Added transparency as color index 255.
52  * 
53  * Revision 1.4  1994/01/17  16:59:12  john
54  * once again...
55  * 
56  * Revision 1.3  1994/01/17  16:51:17  john
57  * Added check so we don't draw outsibe
58  * the source bitmap's v coordinate... kind
59  * of a hack, but works.
60  * 
61  * Revision 1.2  1994/01/12  18:03:26  john
62  * The first iteration of fast scaler..
63  * 
64  * Revision 1.1  1994/01/11  14:48:42  john
65  * Initial revision
66  * 
67  * 
68  */
69
70 #ifdef HAVE_CONFIG_H
71 #include <conf.h>
72 #endif
73
74 #ifdef RCS
75 static char rcsid[] = "$Id: scale.c,v 1.2 2001-01-31 15:17:48 bradleyb Exp $";
76 #endif
77
78 #include <math.h>
79 #include <limits.h>
80 #include <stdio.h>
81 #include <stdlib.h>
82
83 #include "mono.h"
84 #include "fix.h"
85 #include "gr.h"
86 #include "error.h"
87 #include "rle.h"
88
89 #if 0
90 #define TRANSPARENCY_COLOR 255;
91 #endif
92
93 static int Transparency_color = TRANSPARENCY_COLOR;
94
95 #include "scalea.h"
96
97 void rls_stretch_scanline( char * source, char * dest, int XDelta, int YDelta );
98 void rls_stretch_scanline_setup( int XDelta, int YDelta );
99 void scale_bitmap_asm(grs_bitmap *source_bmp, grs_bitmap *dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0,  fix u1, fix v1  );
100 void scale_bitmap_asm_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  );
101 void scale_bitmap_cc_asm(grs_bitmap *source_bmp, grs_bitmap *dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0,  fix u1, fix v1  );
102 void scale_bitmap_cc_asm_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  );
103
104 void scale_row_c( ubyte * sbits, ubyte * dbits, int width, fix u, fix du )
105 {
106         int i;
107         ubyte c;
108
109         for ( i=0; i<width; i++ )       {
110                 c = sbits[ f2i(u) ];
111
112                 if ( c != Transparency_color )
113                         *dbits = c;
114                         
115                 dbits++;
116                 u += du;
117         }
118 }
119
120 #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (fixmuldiv((x)-(x0),(y1)-(y0),(x1)-(x0))+(y0))
121
122 // Scales bitmap, bp, into vertbuf[0] to vertbuf[1]
123 void scale_bitmap(grs_bitmap *bp, grs_point *vertbuf ,int orientation)
124 {
125         grs_bitmap * dbp = &grd_curcanv->cv_bitmap;
126         fix x0, y0, x1, y1;
127         fix u0, v0, u1, v1;
128         fix clipped_x0, clipped_y0, clipped_x1, clipped_y1;
129         fix clipped_u0, clipped_v0, clipped_u1, clipped_v1;
130         fix xmin, xmax, ymin, ymax;
131         int dx0, dy0, dx1, dy1;
132         int dtemp;
133         // Set initial variables....
134
135         x0 = vertbuf[0].x; y0 = vertbuf[0].y;
136         x1 = vertbuf[2].x; y1 = vertbuf[2].y;
137
138         xmin = 0; ymin = 0;
139         xmax = i2f(dbp->bm_w)-fl2f(.5); ymax = i2f(dbp->bm_h)-fl2f(.5);
140
141         u0 = i2f(0); v0 = i2f(0);
142         u1 = i2f(bp->bm_w-1); v1 = i2f(bp->bm_h-1);
143
144         // Check for obviously offscreen bitmaps...
145         if ( (y1<=y0) || (x1<=x0) ) return;
146         if ( (x1<0 ) || (x0>=xmax) ) return;
147         if ( (y1<0 ) || (y0>=ymax) ) return;
148
149         clipped_u0 = u0; clipped_v0 = v0;
150         clipped_u1 = u1; clipped_v1 = v1;
151
152         clipped_x0 = x0; clipped_y0 = y0;
153         clipped_x1 = x1; clipped_y1 = y1;
154
155         // Clip the left, moving u0 right as necessary
156         if ( x0 < xmin )        {
157                 clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1);
158                 clipped_x0 = xmin;
159         }
160
161         // Clip the right, moving u1 left as necessary
162         if ( x1 > xmax )        {
163                 clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1);
164                 clipped_x1 = xmax;
165         }
166
167         // Clip the top, moving v0 down as necessary
168         if ( y0 < ymin )        {
169                 clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1);
170                 clipped_y0 = ymin;
171         }
172
173         // Clip the bottom, moving v1 up as necessary
174         if ( y1 > ymax )        {
175                 clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1);
176                 clipped_y1 = ymax;
177         }
178         
179         dx0 = f2i(clipped_x0); dx1 = f2i(clipped_x1);
180         dy0 = f2i(clipped_y0); dy1 = f2i(clipped_y1);
181
182         if (dx1<=dx0) return;
183         if (dy1<=dy0) return;
184
185         Assert( dx0>=0 );
186         Assert( dy0>=0 );
187         Assert( dx1<dbp->bm_w );
188         Assert( dy1<dbp->bm_h );
189         Assert( f2i(u0)<=f2i(u1) );
190         Assert( f2i(v0)<=f2i(v1) );
191         Assert( f2i(u0)>=0 );
192         Assert( f2i(v0)>=0 );
193         Assert( u1<i2f(bp->bm_w) );
194         Assert( v1<i2f(bp->bm_h) );
195
196         //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) );
197
198         dtemp = f2i(clipped_u1)-f2i(clipped_u0);
199
200         if ( bp->bm_flags & BM_FLAG_RLE )       {
201                 if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) )
202                         scale_bitmap_cc_asm_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
203                 else
204                         scale_bitmap_asm_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
205         } else {
206                 if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) )
207                         scale_bitmap_cc_asm(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
208                 else
209                         scale_bitmap_asm(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
210         }
211 }
212
213
214 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  )
215 {
216         fix u, v, du, dv;
217         int x, y;
218         ubyte * sbits, * dbits;
219
220         du = (u1-u0) / (x1-x0);
221         dv = (v1-v0) / (y1-y0);
222
223         v = v0;
224
225         for (y=y0; y<=y1; y++ )                 {
226                 sbits = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)];
227                 dbits = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
228                 u = u0; 
229                 v += dv;
230                 for (x=x0; x<=x1; x++ )                 {
231                         *dbits++ = sbits[ u >> 16 ];
232                         u += du;
233                 }
234         }
235 }
236
237 void scale_bitmap_asm(grs_bitmap *source_bmp, grs_bitmap *dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0,  fix u1, fix v1  )
238 {
239         fix du, dv, v;
240         int y;
241
242         du = (u1-u0) / (x1-x0);
243         dv = (v1-v0) / (y1-y0);
244
245         v = v0;
246
247         for (y=y0; y<=y1; y++ )                 {
248                 scale_row_asm_transparent( &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)], &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0], x1-x0+1, u0, du );
249                 v += dv;
250         }
251 }
252
253 ubyte scale_rle_data[640];
254
255 void decode_row( grs_bitmap * bmp, int y )
256 {
257         int i, offset=4+bmp->bm_h;
258         
259         for (i=0; i<y; i++ )
260                 offset += bmp->bm_data[4+i];
261         gr_rle_decode( &bmp->bm_data[offset], scale_rle_data );
262 }
263
264 void scale_bitmap_asm_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  )
265 {
266         fix du, dv, v;
267         int y, last_row=-1;
268
269         du = (u1-u0) / (x1-x0);
270         dv = (v1-v0) / (y1-y0);
271
272         v = v0;
273
274         for (y=y0; y<=y1; y++ )                 {
275                 if ( f2i(v) != last_row )       {
276                         last_row = f2i(v);
277                         decode_row( source_bmp, last_row );
278                 }
279                 scale_row_asm_transparent( scale_rle_data, &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0], x1-x0+1, u0, du );
280                 v += dv;
281         }
282 }
283
284
285 void scale_bitmap_cc_asm(grs_bitmap *source_bmp, grs_bitmap *dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0,  fix u1, fix v1  )
286 {
287         fix dv, v;
288         int y;
289
290         dv = (v1-v0) / (y1-y0);
291                 
292         rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) );
293         if ( scale_ydelta_minus_1 < 1 ) return;
294         rls_do_cc_setup_asm();
295
296         v = v0;
297
298         for (y=y0; y<=y1; y++ )                 {
299                 scale_source_ptr = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)+f2i(u0)];
300                 scale_dest_ptr = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
301                 scale_do_cc_scanline();
302                 v += dv;
303         }
304 }
305
306 void scale_bitmap_cc_asm_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  )
307 {
308         fix dv, v;
309         int y, last_row = -1;
310
311         dv = (v1-v0) / (y1-y0);
312                 
313         rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) );
314         if ( scale_ydelta_minus_1 < 1 ) return;
315         rls_do_cc_setup_asm();
316
317         v = v0;
318
319         for (y=y0; y<=y1; y++ )                 {
320                 if ( f2i(v) != last_row )       {
321                         last_row = f2i(v);
322                         decode_row( source_bmp, last_row );
323                 }
324                 //scale_source_ptr = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)+f2i(u0)];
325                 scale_source_ptr = &scale_rle_data[f2i(u0)];
326                 scale_dest_ptr = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
327                 scale_do_cc_scanline();
328                 v += dv;
329         }
330 }
331
332
333
334 // Run-length slice bitmap scan line stretcher 
335
336 void DrawHorizontalRun(char *ScreenPtr, int RunLength, int Color)
337 {
338    int i;
339
340    for (i=0; i<RunLength; i++)
341       *ScreenPtr++ = Color;
342 }
343
344 void rls_stretch_scanline( char * source, char * dest, int XDelta, int YDelta )
345 {
346            int AdjUp, AdjDown, ErrorTerm;
347         int WholeStep, InitialPixelCount, FinalPixelCount, i, RunLength;
348
349       /* X major line */
350       /* Minimum # of pixels in a run in this line */
351       WholeStep = XDelta / YDelta;
352
353       /* Error term adjust each time Y steps by 1; used to tell when one
354          extra pixel should be drawn as part of a run, to account for
355          fractional steps along the X axis per 1-pixel steps along Y */
356       AdjUp = (XDelta % YDelta) * 2;
357
358       /* Error term adjust when the error term turns over, used to factor
359          out the X step made at that time */
360       AdjDown = YDelta * 2;
361
362       /* Initial error term; reflects an initial step of 0.5 along the Y
363          axis */
364       ErrorTerm = (XDelta % YDelta) - (YDelta * 2);
365
366       /* The initial and last runs are partial, because Y advances only 0.5
367          for these runs, rather than 1. Divide one full run, plus the
368          initial pixel, between the initial and last runs */
369       InitialPixelCount = (WholeStep / 2) + 1;
370       FinalPixelCount = InitialPixelCount;
371
372       /* If the basic run length is even and there's no fractional
373          advance, we have one pixel that could go to either the initial
374          or last partial run, which we'll arbitrarily allocate to the
375          last run */
376       if ((AdjUp == 0) && ((WholeStep & 0x01) == 0))
377       {
378          InitialPixelCount--;
379       }
380      /* If there're an odd number of pixels per run, we have 1 pixel that can't
381      be allocated to either the initial or last partial run, so we'll add 0.5
382      to error term so this pixel will be handled by the normal full-run loop */
383       if ((WholeStep & 0x01) != 0)
384       {
385          ErrorTerm += YDelta;
386       }
387       /* Draw the first, partial run of pixels */
388                 //if ( *source != Transparency_color )
389         rep_stosb(dest, InitialPixelCount, *source );
390                 dest += InitialPixelCount;
391                 source++;
392
393       /* Draw all full runs */
394       for (i=0; i<(YDelta-1); i++)
395       {
396          RunLength = WholeStep;  /* run is at least this long */
397
398          /* Advance the error term and add an extra pixel if the error term so indicates */
399          if ((ErrorTerm += AdjUp) > 0)
400          {
401             RunLength++;
402             ErrorTerm -= AdjDown;   /* reset the error term */
403          }
404          /* Draw this scan line's run */
405
406                         //if ( *source != Transparency_color )
407                 rep_stosb(dest, RunLength, *source );
408                         dest += RunLength;
409                         source++;
410
411       }
412
413       /* Draw the final run of pixels */
414                 //if ( *source != Transparency_color )
415               rep_stosb(dest, FinalPixelCount, *source );
416
417       return;
418 }
419
420
421
422
423 void rls_stretch_scanline_setup( int XDelta, int YDelta )
424 {
425                 scale_trans_color = Transparency_color & 0xFF;
426                 scale_ydelta_minus_1 = YDelta - 1;
427
428       /* X major line */
429       /* Minimum # of pixels in a run in this line */
430       scale_whole_step = XDelta / YDelta;
431
432       /* Error term adjust each time Y steps by 1; used to tell when one
433          extra pixel should be drawn as part of a run, to account for
434          fractional steps along the X axis per 1-pixel steps along Y */
435       scale_adj_up = (XDelta % YDelta) * 2;
436
437       /* Error term adjust when the error term turns over, used to factor
438          out the X step made at that time */
439       scale_adj_down = YDelta * 2;
440
441       /* Initial error term; reflects an initial step of 0.5 along the Y
442          axis */
443       scale_error_term = (XDelta % YDelta) - (YDelta * 2);
444
445       /* The initial and last runs are partial, because Y advances only 0.5
446          for these runs, rather than 1. Divide one full run, plus the
447          initial pixel, between the initial and last runs */
448       scale_initial_pixel_count = (scale_whole_step / 2) + 1;
449       scale_final_pixel_count = scale_initial_pixel_count;
450
451       /* If the basic run length is even and there's no fractional
452          advance, we have one pixel that could go to either the initial
453          or last partial run, which we'll arbitrarily allocate to the
454          last run */
455       if ((scale_adj_up == 0) && ((scale_whole_step & 0x01) == 0))
456       {
457          scale_initial_pixel_count--;
458       }
459      /* If there're an odd number of pixels per run, we have 1 pixel that can't
460      be allocated to either the initial or last partial run, so we'll add 0.5
461      to error term so this pixel will be handled by the normal full-run loop */
462       if ((scale_whole_step & 0x01) != 0)
463       {
464          scale_error_term += YDelta;
465       }
466
467 }
468