added cvsignore
[btb/d2x.git] / 2d / scalec.c
1 /* $Id: scalec.c,v 1.3 2002-07-17 21:55:19 bradleyb 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  );
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);
43
44
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
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  )
55 {
56         fix dv, v;
57         int y;
58
59         dv = (v1-v0) / (y1-y0);
60                 
61         rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) );
62         if ( scale_ydelta_minus_1 < 1 ) return;
63
64         v = v0;
65
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();
70                 v += dv;
71         }
72 }
73
74
75
76
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  )
78 {
79         fix dv, v;
80         int y, last_row = -1;
81
82         dv = (v1-v0) / (y1-y0);
83                 
84         rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) );
85         if ( scale_ydelta_minus_1 < 1 ) return;
86
87         v = v0;
88
89         for (y=y0; y<=y1; y++ )                 {
90                 if ( f2i(v) != last_row )       {
91                         last_row = f2i(v);
92                         decode_row( source_bmp, last_row );
93                 }
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();
97                 v += dv;
98         }
99 }
100
101 void rls_stretch_scanline_setup( int XDelta, int YDelta )
102 {
103           scale_ydelta_minus_1 = YDelta - 1;
104
105       /* X major line */
106       /* Minimum # of pixels in a run in this line */
107       scale_whole_step = XDelta / YDelta;
108
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;
113
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;
117
118       /* Initial error term; reflects an initial step of 0.5 along the Y
119          axis */
120       scale_error_term = (XDelta % YDelta) - (YDelta * 2);
121
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;
127
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
131          last run */
132       if ((scale_adj_up == 0) && ((scale_whole_step & 0x01) == 0))
133       {
134          scale_initial_pixel_count--;
135       }
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)
140       {
141          scale_error_term += YDelta;
142       }
143
144 }
145
146 void rls_stretch_scanline()
147 {
148         ubyte   c;
149         int i, j, len, ErrorTerm, x;
150
151         // Setup initial variables
152         ErrorTerm = scale_error_term;
153
154         // Draw the first, partial run of pixels
155
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;
160         } else {
161                 scale_dest_ptr += scale_initial_pixel_count;
162         }
163
164         // Draw all full runs 
165
166         for (j=0; j<scale_ydelta_minus_1; j++)  {
167                 len = scale_whole_step;         // run is at least this long
168
169                 // Advance the error term and add an extra pixel if the error term so indicates
170                 if ((ErrorTerm += scale_adj_up) > 0)    {
171                         len++;
172                         ErrorTerm -= scale_adj_down;   // reset the error term
173                 }
174          
175                 // Draw this run o' pixels
176                 c = *scale_source_ptr++;
177                 if ( c != TRANSPARENCY_COLOR )  {
178
179                         if (len > 3) {                  
180                                 while ((size_t)(scale_dest_ptr) & 0x3) { *scale_dest_ptr++ = c; len--; };
181                                 if (len >= 4) {
182                                         x = (c << 24) | (c << 16) | (c << 8) | c;
183                                         while (len > 4) { *((int *)scale_dest_ptr) = x; scale_dest_ptr += 4; len -= 4; };
184                                 }
185                                 while (len > 0) { *scale_dest_ptr++ = c; len--; };
186                         } else {
187                                 for (i=0; i<len; i++ )
188                                         *scale_dest_ptr++ = c;
189                         }
190                 } else {
191                         scale_dest_ptr += len;
192                 }
193         }
194
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;
200         } else {
201                 scale_dest_ptr += scale_final_pixel_count;
202         }
203 }
204
205 // old stuff here...
206
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  )
208 {
209         fix u, v, du, dv;
210         int x, y;
211         ubyte * sbits, * dbits;
212
213         du = (u1-u0) / (x1-x0);
214         dv = (v1-v0) / (y1-y0);
215
216         v = v0;
217
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];
221                 u = u0; 
222                 v += dv;
223                 for (x=x0; x<=x1; x++ )                 {
224                         *dbits++ = sbits[ u >> 16 ];
225                         u += du;
226                 }
227         }
228 }
229
230 void scale_row_asm_transparent( ubyte * sbits, ubyte * dbits, int width, fix u, fix du )
231 {
232 #if 0
233         int i;
234         ubyte c;
235
236         for (i=0; i<width; i++ )        {
237                 c = sbits[ u >> 16 ];
238                 if ( c!=TRANSPARENCY_COLOR) 
239                         *dbits = c;
240                 dbits++;
241                 u += du;
242         }
243 #endif
244         int i;
245         ubyte c;
246         ubyte *dbits_end = &dbits[width-1];
247
248         if ( du < F1_0 )        {
249                 // Scaling up.
250                 fix next_u;
251                 int next_u_int;
252
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;
257
258 Transparent:
259                 while (1)       {
260                         dbits++;
261                         if ( dbits > dbits_end ) return;
262                         u += du;
263                         if ( u > next_u )       {
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;
268                         }
269                 }
270                 return;
271
272 NonTransparent:
273                 while (1)       {
274                         *dbits++ = c;
275                         if ( dbits > dbits_end ) return;
276                         u += du;
277                         if ( u > next_u )       {
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;
282                         }
283                 }
284                 return;
285
286
287
288         } else {
289                 for ( i=0; i<width; i++ )       {
290                         c = sbits[ f2i(u) ];
291         
292                         if ( c != TRANSPARENCY_COLOR )
293                                 *dbits = c;
294                                 
295                         dbits++;
296                         u += du;
297                 }
298         }
299 }
300
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  )
302 {
303         fix du, dv, v;
304         int y, last_row=-1;
305
306         du = (u1-u0) / (x1-x0);
307         dv = (v1-v0) / (y1-y0);
308
309         v = v0;
310
311         for (y=y0; y<=y1; y++ )                 {
312                 if ( f2i(v) != last_row )       {
313                         last_row = f2i(v);
314                         decode_row( source_bmp, last_row );
315                 }
316                 scale_row_asm_transparent( scale_rle_data, &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0], x1-x0+1, u0, du );
317                 v += dv;
318         }
319 }
320
321 #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (fixmuldiv((x)-(x0),(y1)-(y0),(x1)-(x0))+(y0))
322
323 // Scales bitmap, bp, into vertbuf[0] to vertbuf[1]
324 void scale_bitmap(grs_bitmap *bp, grs_point *vertbuf ,int orientation)
325 {
326         grs_bitmap * dbp = &grd_curcanv->cv_bitmap;
327         fix x0, y0, x1, y1;
328         fix u0, v0, u1, v1;
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;
333         int dtemp;
334         // Set initial variables....
335
336         x0 = vertbuf[0].x; y0 = vertbuf[0].y;
337         x1 = vertbuf[2].x; y1 = vertbuf[2].y;
338
339         xmin = 0; ymin = 0;
340         xmax = i2f(dbp->bm_w)-fl2f(.5); ymax = i2f(dbp->bm_h)-fl2f(.5);
341
342         u0 = i2f(0); v0 = i2f(0);
343         u1 = i2f(bp->bm_w-1); v1 = i2f(bp->bm_h-1);
344
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;
349
350         clipped_u0 = u0; clipped_v0 = v0;
351         clipped_u1 = u1; clipped_v1 = v1;
352
353         clipped_x0 = x0; clipped_y0 = y0;
354         clipped_x1 = x1; clipped_y1 = y1;
355
356         // Clip the left, moving u0 right as necessary
357         if ( x0 < xmin )        {
358                 clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1);
359                 clipped_x0 = xmin;
360         }
361
362         // Clip the right, moving u1 left as necessary
363         if ( x1 > xmax )        {
364                 clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1);
365                 clipped_x1 = xmax;
366         }
367
368         // Clip the top, moving v0 down as necessary
369         if ( y0 < ymin )        {
370                 clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1);
371                 clipped_y0 = ymin;
372         }
373
374         // Clip the bottom, moving v1 up as necessary
375         if ( y1 > ymax )        {
376                 clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1);
377                 clipped_y1 = ymax;
378         }
379         
380         dx0 = f2i(clipped_x0); dx1 = f2i(clipped_x1);
381         dy0 = f2i(clipped_y0); dy1 = f2i(clipped_y1);
382
383         if (dx1<=dx0) return;
384         if (dy1<=dy0) return;
385
386 //      Assert( dx0>=0 );
387 //      Assert( dy0>=0 );
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) );
397
398         dtemp = f2i(clipped_u1)-f2i(clipped_u0);
399
400 #if 0
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  );
403         else
404                 scale_bitmap_c(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
405 #endif
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  );
409                 else
410                         scale_bitmap_c_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
411         } else {
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  );
414                 else
415                         scale_bitmap_c(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
416         }
417 }
418