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 
decode_row(grs_bitmap * bmp,int y)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 
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)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 
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)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 
rls_stretch_scanline_setup(int XDelta,int YDelta)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 
rls_stretch_scanline()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 
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)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 
scale_row_asm_transparent(ubyte * sbits,ubyte * dbits,int width,fix u,fix du)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 
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)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]
scale_bitmap(grs_bitmap * bp,grs_point * vertbuf,int orientation)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 
521