1 /* $Id: scale.c,v 1.3 2002-07-17 21:55:19 bradleyb Exp $ */
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.
16 * Routines for scaling a bitmap.
20 * Revision 1.12 1995/03/14 15:14:11 john
21 * Increased max scanline length to 640.
24 * Revision 1.11 1994/11/27 12:56:39 matt
25 * Took out unneeded include of 3d.h
27 * Revision 1.10 1994/11/18 22:50:25 john
28 * Changed shorts to ints in parameters.
30 * Revision 1.9 1994/11/09 16:35:02 john
31 * First version with working RLE bitmaps.
33 * Revision 1.8 1994/06/09 13:15:17 john
34 * *** empty log message ***
36 * Revision 1.7 1994/06/07 11:47:02 john
37 * Added back in the fast code for scaling up bitmaps.
39 * Revision 1.6 1994/02/18 15:32:36 john
40 * *** empty log message ***
42 * Revision 1.5 1994/01/22 14:35:01 john
43 * Added transparency as color index 255.
45 * Revision 1.4 1994/01/17 16:59:12 john
48 * Revision 1.3 1994/01/17 16:51:17 john
49 * Added check so we don't draw outsibe
50 * the source bitmap's v coordinate... kind
51 * of a hack, but works.
53 * Revision 1.2 1994/01/12 18:03:26 john
54 * The first iteration of fast scaler..
56 * Revision 1.1 1994/01/11 14:48:42 john
67 static char rcsid[] = "$Id: scale.c,v 1.3 2002-07-17 21:55:19 bradleyb Exp $";
82 #define TRANSPARENCY_COLOR 255;
85 static int Transparency_color = TRANSPARENCY_COLOR;
89 void rls_stretch_scanline( char * source, char * dest, int XDelta, int YDelta );
90 void rls_stretch_scanline_setup( int XDelta, int YDelta );
91 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 );
92 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 );
93 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 );
94 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 );
96 void scale_row_c( ubyte * sbits, ubyte * dbits, int width, fix u, fix du )
101 for ( i=0; i<width; i++ ) {
104 if ( c != Transparency_color )
112 #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (fixmuldiv((x)-(x0),(y1)-(y0),(x1)-(x0))+(y0))
114 // Scales bitmap, bp, into vertbuf[0] to vertbuf[1]
115 void scale_bitmap(grs_bitmap *bp, grs_point *vertbuf ,int orientation)
117 grs_bitmap * dbp = &grd_curcanv->cv_bitmap;
120 fix clipped_x0, clipped_y0, clipped_x1, clipped_y1;
121 fix clipped_u0, clipped_v0, clipped_u1, clipped_v1;
122 fix xmin, xmax, ymin, ymax;
123 int dx0, dy0, dx1, dy1;
125 // Set initial variables....
127 x0 = vertbuf[0].x; y0 = vertbuf[0].y;
128 x1 = vertbuf[2].x; y1 = vertbuf[2].y;
131 xmax = i2f(dbp->bm_w)-fl2f(.5); ymax = i2f(dbp->bm_h)-fl2f(.5);
133 u0 = i2f(0); v0 = i2f(0);
134 u1 = i2f(bp->bm_w-1); v1 = i2f(bp->bm_h-1);
136 // Check for obviously offscreen bitmaps...
137 if ( (y1<=y0) || (x1<=x0) ) return;
138 if ( (x1<0 ) || (x0>=xmax) ) return;
139 if ( (y1<0 ) || (y0>=ymax) ) return;
141 clipped_u0 = u0; clipped_v0 = v0;
142 clipped_u1 = u1; clipped_v1 = v1;
144 clipped_x0 = x0; clipped_y0 = y0;
145 clipped_x1 = x1; clipped_y1 = y1;
147 // Clip the left, moving u0 right as necessary
149 clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1);
153 // Clip the right, moving u1 left as necessary
155 clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1);
159 // Clip the top, moving v0 down as necessary
161 clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1);
165 // Clip the bottom, moving v1 up as necessary
167 clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1);
171 dx0 = f2i(clipped_x0); dx1 = f2i(clipped_x1);
172 dy0 = f2i(clipped_y0); dy1 = f2i(clipped_y1);
174 if (dx1<=dx0) return;
175 if (dy1<=dy0) return;
179 Assert( dx1<dbp->bm_w );
180 Assert( dy1<dbp->bm_h );
181 Assert( f2i(u0)<=f2i(u1) );
182 Assert( f2i(v0)<=f2i(v1) );
183 Assert( f2i(u0)>=0 );
184 Assert( f2i(v0)>=0 );
185 Assert( u1<i2f(bp->bm_w) );
186 Assert( v1<i2f(bp->bm_h) );
188 //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) );
190 dtemp = f2i(clipped_u1)-f2i(clipped_u0);
192 if ( bp->bm_flags & BM_FLAG_RLE ) {
193 if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) )
194 scale_bitmap_cc_asm_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
196 scale_bitmap_asm_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
198 if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) )
199 scale_bitmap_cc_asm(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
201 scale_bitmap_asm(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
206 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 )
210 ubyte * sbits, * dbits;
212 du = (u1-u0) / (x1-x0);
213 dv = (v1-v0) / (y1-y0);
217 for (y=y0; y<=y1; y++ ) {
218 sbits = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)];
219 dbits = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
222 for (x=x0; x<=x1; x++ ) {
223 *dbits++ = sbits[ u >> 16 ];
229 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 )
234 du = (u1-u0) / (x1-x0);
235 dv = (v1-v0) / (y1-y0);
239 for (y=y0; y<=y1; y++ ) {
240 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 );
245 ubyte scale_rle_data[640];
247 void decode_row( grs_bitmap * bmp, int y )
249 int i, offset=4+bmp->bm_h;
252 offset += bmp->bm_data[4+i];
253 gr_rle_decode( &bmp->bm_data[offset], scale_rle_data );
256 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 )
261 du = (u1-u0) / (x1-x0);
262 dv = (v1-v0) / (y1-y0);
266 for (y=y0; y<=y1; y++ ) {
267 if ( f2i(v) != last_row ) {
269 decode_row( source_bmp, last_row );
271 scale_row_asm_transparent( scale_rle_data, &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0], x1-x0+1, u0, du );
277 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 )
282 dv = (v1-v0) / (y1-y0);
284 rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) );
285 if ( scale_ydelta_minus_1 < 1 ) return;
286 rls_do_cc_setup_asm();
290 for (y=y0; y<=y1; y++ ) {
291 scale_source_ptr = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)+f2i(u0)];
292 scale_dest_ptr = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
293 scale_do_cc_scanline();
298 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 )
301 int y, last_row = -1;
303 dv = (v1-v0) / (y1-y0);
305 rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) );
306 if ( scale_ydelta_minus_1 < 1 ) return;
307 rls_do_cc_setup_asm();
311 for (y=y0; y<=y1; y++ ) {
312 if ( f2i(v) != last_row ) {
314 decode_row( source_bmp, last_row );
316 //scale_source_ptr = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)+f2i(u0)];
317 scale_source_ptr = &scale_rle_data[f2i(u0)];
318 scale_dest_ptr = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
319 scale_do_cc_scanline();
326 // Run-length slice bitmap scan line stretcher
328 void DrawHorizontalRun(char *ScreenPtr, int RunLength, int Color)
332 for (i=0; i<RunLength; i++)
333 *ScreenPtr++ = Color;
336 void rls_stretch_scanline( char * source, char * dest, int XDelta, int YDelta )
338 int AdjUp, AdjDown, ErrorTerm;
339 int WholeStep, InitialPixelCount, FinalPixelCount, i, RunLength;
342 /* Minimum # of pixels in a run in this line */
343 WholeStep = XDelta / YDelta;
345 /* Error term adjust each time Y steps by 1; used to tell when one
346 extra pixel should be drawn as part of a run, to account for
347 fractional steps along the X axis per 1-pixel steps along Y */
348 AdjUp = (XDelta % YDelta) * 2;
350 /* Error term adjust when the error term turns over, used to factor
351 out the X step made at that time */
352 AdjDown = YDelta * 2;
354 /* Initial error term; reflects an initial step of 0.5 along the Y
356 ErrorTerm = (XDelta % YDelta) - (YDelta * 2);
358 /* The initial and last runs are partial, because Y advances only 0.5
359 for these runs, rather than 1. Divide one full run, plus the
360 initial pixel, between the initial and last runs */
361 InitialPixelCount = (WholeStep / 2) + 1;
362 FinalPixelCount = InitialPixelCount;
364 /* If the basic run length is even and there's no fractional
365 advance, we have one pixel that could go to either the initial
366 or last partial run, which we'll arbitrarily allocate to the
368 if ((AdjUp == 0) && ((WholeStep & 0x01) == 0))
372 /* If there're an odd number of pixels per run, we have 1 pixel that can't
373 be allocated to either the initial or last partial run, so we'll add 0.5
374 to error term so this pixel will be handled by the normal full-run loop */
375 if ((WholeStep & 0x01) != 0)
379 /* Draw the first, partial run of pixels */
380 //if ( *source != Transparency_color )
381 rep_stosb(dest, InitialPixelCount, *source );
382 dest += InitialPixelCount;
385 /* Draw all full runs */
386 for (i=0; i<(YDelta-1); i++)
388 RunLength = WholeStep; /* run is at least this long */
390 /* Advance the error term and add an extra pixel if the error term so indicates */
391 if ((ErrorTerm += AdjUp) > 0)
394 ErrorTerm -= AdjDown; /* reset the error term */
396 /* Draw this scan line's run */
398 //if ( *source != Transparency_color )
399 rep_stosb(dest, RunLength, *source );
405 /* Draw the final run of pixels */
406 //if ( *source != Transparency_color )
407 rep_stosb(dest, FinalPixelCount, *source );
415 void rls_stretch_scanline_setup( int XDelta, int YDelta )
417 scale_trans_color = Transparency_color & 0xFF;
418 scale_ydelta_minus_1 = YDelta - 1;
421 /* Minimum # of pixels in a run in this line */
422 scale_whole_step = XDelta / YDelta;
424 /* Error term adjust each time Y steps by 1; used to tell when one
425 extra pixel should be drawn as part of a run, to account for
426 fractional steps along the X axis per 1-pixel steps along Y */
427 scale_adj_up = (XDelta % YDelta) * 2;
429 /* Error term adjust when the error term turns over, used to factor
430 out the X step made at that time */
431 scale_adj_down = YDelta * 2;
433 /* Initial error term; reflects an initial step of 0.5 along the Y
435 scale_error_term = (XDelta % YDelta) - (YDelta * 2);
437 /* The initial and last runs are partial, because Y advances only 0.5
438 for these runs, rather than 1. Divide one full run, plus the
439 initial pixel, between the initial and last runs */
440 scale_initial_pixel_count = (scale_whole_step / 2) + 1;
441 scale_final_pixel_count = scale_initial_pixel_count;
443 /* If the basic run length is even and there's no fractional
444 advance, we have one pixel that could go to either the initial
445 or last partial run, which we'll arbitrarily allocate to the
447 if ((scale_adj_up == 0) && ((scale_whole_step & 0x01) == 0))
449 scale_initial_pixel_count--;
451 /* If there're an odd number of pixels per run, we have 1 pixel that can't
452 be allocated to either the initial or last partial run, so we'll add 0.5
453 to error term so this pixel will be handled by the normal full-run loop */
454 if ((scale_whole_step & 0x01) != 0)
456 scale_error_term += YDelta;