1 /* $Id: scalec.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.
24 // John's new stuff below here....
27 int scale_initial_pixel_count;
30 int scale_final_pixel_count;
31 int scale_ydelta_minus_1;
33 ubyte * scale_source_ptr;
34 ubyte * scale_dest_ptr;
37 ubyte scale_rle_data[640];
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 );
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 );
41 void rls_stretch_scanline_setup( int XDelta, int YDelta );
42 void rls_stretch_scanline(void);
45 void decode_row( grs_bitmap * bmp, int y )
47 int i, offset=4+bmp->bm_h;
50 offset += bmp->bm_data[4+i];
51 gr_rle_decode( &bmp->bm_data[offset], scale_rle_data );
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 )
59 dv = (v1-v0) / (y1-y0);
61 rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) );
62 if ( scale_ydelta_minus_1 < 1 ) return;
66 for (y=y0; y<=y1; y++ ) {
67 scale_source_ptr = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)+f2i(u0)];
68 scale_dest_ptr = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
69 rls_stretch_scanline();
77 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 )
82 dv = (v1-v0) / (y1-y0);
84 rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) );
85 if ( scale_ydelta_minus_1 < 1 ) return;
89 for (y=y0; y<=y1; y++ ) {
90 if ( f2i(v) != last_row ) {
92 decode_row( source_bmp, last_row );
94 scale_source_ptr = &scale_rle_data[f2i(u0)];
95 scale_dest_ptr = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
96 rls_stretch_scanline();
101 void rls_stretch_scanline_setup( int XDelta, int YDelta )
103 scale_ydelta_minus_1 = YDelta - 1;
106 /* Minimum # of pixels in a run in this line */
107 scale_whole_step = XDelta / YDelta;
109 /* Error term adjust each time Y steps by 1; used to tell when one
110 extra pixel should be drawn as part of a run, to account for
111 fractional steps along the X axis per 1-pixel steps along Y */
112 scale_adj_up = (XDelta % YDelta) * 2;
114 /* Error term adjust when the error term turns over, used to factor
115 out the X step made at that time */
116 scale_adj_down = YDelta * 2;
118 /* Initial error term; reflects an initial step of 0.5 along the Y
120 scale_error_term = (XDelta % YDelta) - (YDelta * 2);
122 /* The initial and last runs are partial, because Y advances only 0.5
123 for these runs, rather than 1. Divide one full run, plus the
124 initial pixel, between the initial and last runs */
125 scale_initial_pixel_count = (scale_whole_step / 2) + 1;
126 scale_final_pixel_count = scale_initial_pixel_count;
128 /* If the basic run length is even and there's no fractional
129 advance, we have one pixel that could go to either the initial
130 or last partial run, which we'll arbitrarily allocate to the
132 if ((scale_adj_up == 0) && ((scale_whole_step & 0x01) == 0))
134 scale_initial_pixel_count--;
136 /* If there're an odd number of pixels per run, we have 1 pixel that can't
137 be allocated to either the initial or last partial run, so we'll add 0.5
138 to error term so this pixel will be handled by the normal full-run loop */
139 if ((scale_whole_step & 0x01) != 0)
141 scale_error_term += YDelta;
146 void rls_stretch_scanline()
149 int i, j, len, ErrorTerm, x;
151 // Setup initial variables
152 ErrorTerm = scale_error_term;
154 // Draw the first, partial run of pixels
156 c = *scale_source_ptr++;
157 if ( c != TRANSPARENCY_COLOR ) {
158 for (i=0; i<scale_initial_pixel_count; i++ )
159 *scale_dest_ptr++ = c;
161 scale_dest_ptr += scale_initial_pixel_count;
164 // Draw all full runs
166 for (j=0; j<scale_ydelta_minus_1; j++) {
167 len = scale_whole_step; // run is at least this long
169 // Advance the error term and add an extra pixel if the error term so indicates
170 if ((ErrorTerm += scale_adj_up) > 0) {
172 ErrorTerm -= scale_adj_down; // reset the error term
175 // Draw this run o' pixels
176 c = *scale_source_ptr++;
177 if ( c != TRANSPARENCY_COLOR ) {
180 while ((size_t)(scale_dest_ptr) & 0x3) { *scale_dest_ptr++ = c; len--; };
182 x = (c << 24) | (c << 16) | (c << 8) | c;
183 while (len > 4) { *((int *)scale_dest_ptr) = x; scale_dest_ptr += 4; len -= 4; };
185 while (len > 0) { *scale_dest_ptr++ = c; len--; };
187 for (i=0; i<len; i++ )
188 *scale_dest_ptr++ = c;
191 scale_dest_ptr += len;
195 // Draw the final run of pixels
196 c = *scale_source_ptr++;
197 if ( c != TRANSPARENCY_COLOR ) {
198 for (i=0; i<scale_final_pixel_count; i++ )
199 *scale_dest_ptr++ = c;
201 scale_dest_ptr += scale_final_pixel_count;
207 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 )
211 ubyte * sbits, * dbits;
213 du = (u1-u0) / (x1-x0);
214 dv = (v1-v0) / (y1-y0);
218 for (y=y0; y<=y1; y++ ) {
219 sbits = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)];
220 dbits = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
223 for (x=x0; x<=x1; x++ ) {
224 *dbits++ = sbits[ u >> 16 ];
230 void scale_row_asm_transparent( ubyte * sbits, ubyte * dbits, int width, fix u, fix du )
236 for (i=0; i<width; i++ ) {
237 c = sbits[ u >> 16 ];
238 if ( c!=TRANSPARENCY_COLOR)
246 ubyte *dbits_end = &dbits[width-1];
253 next_u_int = f2i(u)+1;
254 c = sbits[ next_u_int ];
255 next_u = i2f(next_u_int);
256 if ( c != TRANSPARENCY_COLOR ) goto NonTransparent;
261 if ( dbits > dbits_end ) return;
264 next_u_int = f2i(u)+1;
265 c = sbits[ next_u_int ];
266 next_u = i2f(next_u_int);
267 if ( c != TRANSPARENCY_COLOR ) goto NonTransparent;
275 if ( dbits > dbits_end ) return;
278 next_u_int = f2i(u)+1;
279 c = sbits[ next_u_int ];
280 next_u = i2f(next_u_int);
281 if ( c == TRANSPARENCY_COLOR ) goto Transparent;
289 for ( i=0; i<width; i++ ) {
292 if ( c != TRANSPARENCY_COLOR )
301 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 )
306 du = (u1-u0) / (x1-x0);
307 dv = (v1-v0) / (y1-y0);
311 for (y=y0; y<=y1; y++ ) {
312 if ( f2i(v) != last_row ) {
314 decode_row( source_bmp, last_row );
316 scale_row_asm_transparent( scale_rle_data, &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0], x1-x0+1, u0, du );
321 #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (fixmuldiv((x)-(x0),(y1)-(y0),(x1)-(x0))+(y0))
323 // Scales bitmap, bp, into vertbuf[0] to vertbuf[1]
324 void scale_bitmap(grs_bitmap *bp, grs_point *vertbuf ,int orientation)
326 grs_bitmap * dbp = &grd_curcanv->cv_bitmap;
329 fix clipped_x0, clipped_y0, clipped_x1, clipped_y1;
330 fix clipped_u0, clipped_v0, clipped_u1, clipped_v1;
331 fix xmin, xmax, ymin, ymax;
332 int dx0, dy0, dx1, dy1;
334 // Set initial variables....
336 x0 = vertbuf[0].x; y0 = vertbuf[0].y;
337 x1 = vertbuf[2].x; y1 = vertbuf[2].y;
340 xmax = i2f(dbp->bm_w)-fl2f(.5); ymax = i2f(dbp->bm_h)-fl2f(.5);
342 u0 = i2f(0); v0 = i2f(0);
343 u1 = i2f(bp->bm_w-1); v1 = i2f(bp->bm_h-1);
345 // Check for obviously offscreen bitmaps...
346 if ( (y1<=y0) || (x1<=x0) ) return;
347 if ( (x1<0 ) || (x0>=xmax) ) return;
348 if ( (y1<0 ) || (y0>=ymax) ) return;
350 clipped_u0 = u0; clipped_v0 = v0;
351 clipped_u1 = u1; clipped_v1 = v1;
353 clipped_x0 = x0; clipped_y0 = y0;
354 clipped_x1 = x1; clipped_y1 = y1;
356 // Clip the left, moving u0 right as necessary
358 clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1);
362 // Clip the right, moving u1 left as necessary
364 clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1);
368 // Clip the top, moving v0 down as necessary
370 clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1);
374 // Clip the bottom, moving v1 up as necessary
376 clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1);
380 dx0 = f2i(clipped_x0); dx1 = f2i(clipped_x1);
381 dy0 = f2i(clipped_y0); dy1 = f2i(clipped_y1);
383 if (dx1<=dx0) return;
384 if (dy1<=dy0) return;
388 // Assert( dx1<dbp->bm_w );
389 // Assert( dy1<dbp->bm_h );
390 // Assert( f2i(u0)<=f2i(u1) );
391 // Assert( f2i(v0)<=f2i(v1) );
392 // Assert( f2i(u0)>=0 );
393 // Assert( f2i(v0)>=0 );
394 // Assert( u1<i2f(bp->bm_w) );
395 // Assert( v1<i2f(bp->bm_h) );
396 //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) );
398 dtemp = f2i(clipped_u1)-f2i(clipped_u0);
401 if ( bp->bm_flags & BM_FLAG_RLE )
402 scale_bitmap_c_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
404 scale_bitmap_c(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
406 if ( bp->bm_flags & BM_FLAG_RLE ) {
407 if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) )
408 scale_up_bitmap_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
410 scale_bitmap_c_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
412 if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) )
413 scale_up_bitmap(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );
415 scale_bitmap_c(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1 );