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.
14 * $Source: /cvs/cvsroot/d2x/2d/scale.c,v $
17 * $Date: 2001-01-31 15:17:48 $
19 * Routines for scaling a bitmap.
21 * $Log: not supported by cvs2svn $
22 * Revision 1.1.1.1 2001/01/19 03:29:57 bradleyb
25 * Revision 1.1.1.1 1999/06/14 21:57:36 donut
26 * Import of d1x 1.37 source.
28 * Revision 1.12 1995/03/14 15:14:11 john
29 * Increased max scanline length to 640.
32 * Revision 1.11 1994/11/27 12:56:39 matt
33 * Took out unneeded include of 3d.h
35 * Revision 1.10 1994/11/18 22:50:25 john
36 * Changed shorts to ints in parameters.
38 * Revision 1.9 1994/11/09 16:35:02 john
39 * First version with working RLE bitmaps.
41 * Revision 1.8 1994/06/09 13:15:17 john
42 * *** empty log message ***
44 * Revision 1.7 1994/06/07 11:47:02 john
45 * Added back in the fast code for scaling up bitmaps.
47 * Revision 1.6 1994/02/18 15:32:36 john
48 * *** empty log message ***
50 * Revision 1.5 1994/01/22 14:35:01 john
51 * Added transparency as color index 255.
53 * Revision 1.4 1994/01/17 16:59:12 john
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.
61 * Revision 1.2 1994/01/12 18:03:26 john
62 * The first iteration of fast scaler..
64 * Revision 1.1 1994/01/11 14:48:42 john
75 static char rcsid[] = "$Id: scale.c,v 1.2 2001-01-31 15:17:48 bradleyb Exp $";
90 #define TRANSPARENCY_COLOR 255;
93 static int Transparency_color = TRANSPARENCY_COLOR;
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 );
104 void scale_row_c( ubyte * sbits, ubyte * dbits, int width, fix u, fix du )
109 for ( i=0; i<width; i++ ) {
112 if ( c != Transparency_color )
120 #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (fixmuldiv((x)-(x0),(y1)-(y0),(x1)-(x0))+(y0))
122 // Scales bitmap, bp, into vertbuf[0] to vertbuf[1]
123 void scale_bitmap(grs_bitmap *bp, grs_point *vertbuf ,int orientation)
125 grs_bitmap * dbp = &grd_curcanv->cv_bitmap;
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;
133 // Set initial variables....
135 x0 = vertbuf[0].x; y0 = vertbuf[0].y;
136 x1 = vertbuf[2].x; y1 = vertbuf[2].y;
139 xmax = i2f(dbp->bm_w)-fl2f(.5); ymax = i2f(dbp->bm_h)-fl2f(.5);
141 u0 = i2f(0); v0 = i2f(0);
142 u1 = i2f(bp->bm_w-1); v1 = i2f(bp->bm_h-1);
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;
149 clipped_u0 = u0; clipped_v0 = v0;
150 clipped_u1 = u1; clipped_v1 = v1;
152 clipped_x0 = x0; clipped_y0 = y0;
153 clipped_x1 = x1; clipped_y1 = y1;
155 // Clip the left, moving u0 right as necessary
157 clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1);
161 // Clip the right, moving u1 left as necessary
163 clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1);
167 // Clip the top, moving v0 down as necessary
169 clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1);
173 // Clip the bottom, moving v1 up as necessary
175 clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1);
179 dx0 = f2i(clipped_x0); dx1 = f2i(clipped_x1);
180 dy0 = f2i(clipped_y0); dy1 = f2i(clipped_y1);
182 if (dx1<=dx0) return;
183 if (dy1<=dy0) return;
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) );
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) );
198 dtemp = f2i(clipped_u1)-f2i(clipped_u0);
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 );
204 scale_bitmap_asm_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
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 );
209 scale_bitmap_asm(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
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 )
218 ubyte * sbits, * dbits;
220 du = (u1-u0) / (x1-x0);
221 dv = (v1-v0) / (y1-y0);
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];
230 for (x=x0; x<=x1; x++ ) {
231 *dbits++ = sbits[ u >> 16 ];
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 )
242 du = (u1-u0) / (x1-x0);
243 dv = (v1-v0) / (y1-y0);
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 );
253 ubyte scale_rle_data[640];
255 void decode_row( grs_bitmap * bmp, int y )
257 int i, offset=4+bmp->bm_h;
260 offset += bmp->bm_data[4+i];
261 gr_rle_decode( &bmp->bm_data[offset], scale_rle_data );
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 )
269 du = (u1-u0) / (x1-x0);
270 dv = (v1-v0) / (y1-y0);
274 for (y=y0; y<=y1; y++ ) {
275 if ( f2i(v) != last_row ) {
277 decode_row( source_bmp, last_row );
279 scale_row_asm_transparent( scale_rle_data, &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0], x1-x0+1, u0, du );
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 )
290 dv = (v1-v0) / (y1-y0);
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();
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();
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 )
309 int y, last_row = -1;
311 dv = (v1-v0) / (y1-y0);
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();
319 for (y=y0; y<=y1; y++ ) {
320 if ( f2i(v) != last_row ) {
322 decode_row( source_bmp, last_row );
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();
334 // Run-length slice bitmap scan line stretcher
336 void DrawHorizontalRun(char *ScreenPtr, int RunLength, int Color)
340 for (i=0; i<RunLength; i++)
341 *ScreenPtr++ = Color;
344 void rls_stretch_scanline( char * source, char * dest, int XDelta, int YDelta )
346 int AdjUp, AdjDown, ErrorTerm;
347 int WholeStep, InitialPixelCount, FinalPixelCount, i, RunLength;
350 /* Minimum # of pixels in a run in this line */
351 WholeStep = XDelta / YDelta;
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;
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;
362 /* Initial error term; reflects an initial step of 0.5 along the Y
364 ErrorTerm = (XDelta % YDelta) - (YDelta * 2);
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;
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
376 if ((AdjUp == 0) && ((WholeStep & 0x01) == 0))
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)
387 /* Draw the first, partial run of pixels */
388 //if ( *source != Transparency_color )
389 rep_stosb(dest, InitialPixelCount, *source );
390 dest += InitialPixelCount;
393 /* Draw all full runs */
394 for (i=0; i<(YDelta-1); i++)
396 RunLength = WholeStep; /* run is at least this long */
398 /* Advance the error term and add an extra pixel if the error term so indicates */
399 if ((ErrorTerm += AdjUp) > 0)
402 ErrorTerm -= AdjDown; /* reset the error term */
404 /* Draw this scan line's run */
406 //if ( *source != Transparency_color )
407 rep_stosb(dest, RunLength, *source );
413 /* Draw the final run of pixels */
414 //if ( *source != Transparency_color )
415 rep_stosb(dest, FinalPixelCount, *source );
423 void rls_stretch_scanline_setup( int XDelta, int YDelta )
425 scale_trans_color = Transparency_color & 0xFF;
426 scale_ydelta_minus_1 = YDelta - 1;
429 /* Minimum # of pixels in a run in this line */
430 scale_whole_step = XDelta / YDelta;
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;
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;
441 /* Initial error term; reflects an initial step of 0.5 along the Y
443 scale_error_term = (XDelta % YDelta) - (YDelta * 2);
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;
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
455 if ((scale_adj_up == 0) && ((scale_whole_step & 0x01) == 0))
457 scale_initial_pixel_count--;
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)
464 scale_error_term += YDelta;