improved automake config. make dist, VPATH builds, ...
[btb/d2x.git] / 2d / scalec.c
1 /*
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.
12 */
13 #include <conf.h>
14 #include <stdlib.h>
15 #include "gr.h"
16 #include "grdef.h"
17 #include "rle.h"
18
19 // John's new stuff below here....
20
21 int scale_error_term;
22 int scale_initial_pixel_count;
23 int scale_adj_up;
24 int scale_adj_down;
25 int scale_final_pixel_count;
26 int scale_ydelta_minus_1;
27 int scale_whole_step;
28 ubyte * scale_source_ptr;
29 ubyte * scale_dest_ptr;
30
31
32 ubyte scale_rle_data[640];
33
34 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  );
35 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  );
36 void rls_stretch_scanline_setup( int XDelta, int YDelta );
37 void rls_stretch_scanline(void);
38
39
40 void decode_row( grs_bitmap * bmp, int y )
41 {
42         int i, offset=4+bmp->bm_h;
43         
44         for (i=0; i<y; i++ )
45                 offset += bmp->bm_data[4+i];
46         gr_rle_decode( &bmp->bm_data[offset], scale_rle_data );
47 }
48
49 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  )
50 {
51         fix dv, v;
52         int y;
53
54         dv = (v1-v0) / (y1-y0);
55                 
56         rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) );
57         if ( scale_ydelta_minus_1 < 1 ) return;
58
59         v = v0;
60
61         for (y=y0; y<=y1; y++ )                 {
62                 scale_source_ptr = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)+f2i(u0)];
63                 scale_dest_ptr = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
64                 rls_stretch_scanline();
65                 v += dv;
66         }
67 }
68
69
70
71
72 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  )
73 {
74         fix dv, v;
75         int y, last_row = -1;
76
77         dv = (v1-v0) / (y1-y0);
78                 
79         rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) );
80         if ( scale_ydelta_minus_1 < 1 ) return;
81
82         v = v0;
83
84         for (y=y0; y<=y1; y++ )                 {
85                 if ( f2i(v) != last_row )       {
86                         last_row = f2i(v);
87                         decode_row( source_bmp, last_row );
88                 }
89                 scale_source_ptr = &scale_rle_data[f2i(u0)];
90                 scale_dest_ptr = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
91                 rls_stretch_scanline();
92                 v += dv;
93         }
94 }
95
96 void rls_stretch_scanline_setup( int XDelta, int YDelta )
97 {
98           scale_ydelta_minus_1 = YDelta - 1;
99
100       /* X major line */
101       /* Minimum # of pixels in a run in this line */
102       scale_whole_step = XDelta / YDelta;
103
104       /* Error term adjust each time Y steps by 1; used to tell when one
105          extra pixel should be drawn as part of a run, to account for
106          fractional steps along the X axis per 1-pixel steps along Y */
107       scale_adj_up = (XDelta % YDelta) * 2;
108
109       /* Error term adjust when the error term turns over, used to factor
110          out the X step made at that time */
111       scale_adj_down = YDelta * 2;
112
113       /* Initial error term; reflects an initial step of 0.5 along the Y
114          axis */
115       scale_error_term = (XDelta % YDelta) - (YDelta * 2);
116
117       /* The initial and last runs are partial, because Y advances only 0.5
118          for these runs, rather than 1. Divide one full run, plus the
119          initial pixel, between the initial and last runs */
120       scale_initial_pixel_count = (scale_whole_step / 2) + 1;
121       scale_final_pixel_count = scale_initial_pixel_count;
122
123       /* If the basic run length is even and there's no fractional
124          advance, we have one pixel that could go to either the initial
125          or last partial run, which we'll arbitrarily allocate to the
126          last run */
127       if ((scale_adj_up == 0) && ((scale_whole_step & 0x01) == 0))
128       {
129          scale_initial_pixel_count--;
130       }
131      /* If there're an odd number of pixels per run, we have 1 pixel that can't
132      be allocated to either the initial or last partial run, so we'll add 0.5
133      to error term so this pixel will be handled by the normal full-run loop */
134       if ((scale_whole_step & 0x01) != 0)
135       {
136          scale_error_term += YDelta;
137       }
138
139 }
140
141 void rls_stretch_scanline()
142 {
143         ubyte   c;
144         int i, j, len, ErrorTerm, x;
145
146         // Setup initial variables
147         ErrorTerm = scale_error_term;
148
149         // Draw the first, partial run of pixels
150
151         c = *scale_source_ptr++;
152         if ( c != TRANSPARENCY_COLOR )  {
153                 for (i=0; i<scale_initial_pixel_count; i++ )
154                         *scale_dest_ptr++ = c;
155         } else {
156                 scale_dest_ptr += scale_initial_pixel_count;
157         }
158
159         // Draw all full runs 
160
161         for (j=0; j<scale_ydelta_minus_1; j++)  {
162                 len = scale_whole_step;         // run is at least this long
163
164                 // Advance the error term and add an extra pixel if the error term so indicates
165                 if ((ErrorTerm += scale_adj_up) > 0)    {
166                         len++;
167                         ErrorTerm -= scale_adj_down;   // reset the error term
168                 }
169          
170                 // Draw this run o' pixels
171                 c = *scale_source_ptr++;
172                 if ( c != TRANSPARENCY_COLOR )  {
173
174                         if (len > 3) {                  
175                                 while ((size_t)(scale_dest_ptr) & 0x3) { *scale_dest_ptr++ = c; len--; };
176                                 if (len >= 4) {
177                                         x = (c << 24) | (c << 16) | (c << 8) | c;
178                                         while (len > 4) { *((int *)scale_dest_ptr) = x; scale_dest_ptr += 4; len -= 4; };
179                                 }
180                                 while (len > 0) { *scale_dest_ptr++ = c; len--; };
181                         } else {
182                                 for (i=0; i<len; i++ )
183                                         *scale_dest_ptr++ = c;
184                         }
185                 } else {
186                         scale_dest_ptr += len;
187                 }
188         }
189
190         // Draw the final run of pixels
191         c = *scale_source_ptr++;
192         if ( c != TRANSPARENCY_COLOR )  {
193                 for (i=0; i<scale_final_pixel_count; i++ )
194                         *scale_dest_ptr++ = c;
195         } else {
196                 scale_dest_ptr += scale_final_pixel_count;
197         }
198 }
199
200 // old stuff here...
201
202 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  )
203 {
204         fix u, v, du, dv;
205         int x, y;
206         ubyte * sbits, * dbits;
207
208         du = (u1-u0) / (x1-x0);
209         dv = (v1-v0) / (y1-y0);
210
211         v = v0;
212
213         for (y=y0; y<=y1; y++ )                 {
214                 sbits = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)];
215                 dbits = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0];
216                 u = u0; 
217                 v += dv;
218                 for (x=x0; x<=x1; x++ )                 {
219                         *dbits++ = sbits[ u >> 16 ];
220                         u += du;
221                 }
222         }
223 }
224
225 void scale_row_asm_transparent( ubyte * sbits, ubyte * dbits, int width, fix u, fix du )
226 {
227 #if 0
228         int i;
229         ubyte c;
230
231         for (i=0; i<width; i++ )        {
232                 c = sbits[ u >> 16 ];
233                 if ( c!=TRANSPARENCY_COLOR) 
234                         *dbits = c;
235                 dbits++;
236                 u += du;
237         }
238 #endif
239         int i;
240         ubyte c;
241         ubyte *dbits_end = &dbits[width-1];
242
243         if ( du < F1_0 )        {
244                 // Scaling up.
245                 fix next_u;
246                 int next_u_int;
247
248                 next_u_int = f2i(u)+1;
249                 c = sbits[ next_u_int ];
250                 next_u = i2f(next_u_int);
251                 if ( c != TRANSPARENCY_COLOR ) goto NonTransparent;
252
253 Transparent:
254                 while (1)       {
255                         dbits++;
256                         if ( dbits > dbits_end ) return;
257                         u += du;
258                         if ( u > next_u )       {
259                                 next_u_int = f2i(u)+1;
260                                 c = sbits[ next_u_int ];
261                                 next_u = i2f(next_u_int);
262                                 if ( c != TRANSPARENCY_COLOR ) goto NonTransparent;
263                         }
264                 }
265                 return;
266
267 NonTransparent:
268                 while (1)       {
269                         *dbits++ = c;
270                         if ( dbits > dbits_end ) return;
271                         u += du;
272                         if ( u > next_u )       {
273                                 next_u_int = f2i(u)+1;
274                                 c = sbits[ next_u_int ];
275                                 next_u = i2f(next_u_int);
276                                 if ( c == TRANSPARENCY_COLOR ) goto Transparent;
277                         }
278                 }
279                 return;
280
281
282
283         } else {
284                 for ( i=0; i<width; i++ )       {
285                         c = sbits[ f2i(u) ];
286         
287                         if ( c != TRANSPARENCY_COLOR )
288                                 *dbits = c;
289                                 
290                         dbits++;
291                         u += du;
292                 }
293         }
294 }
295
296 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  )
297 {
298         fix du, dv, v;
299         int y, last_row=-1;
300
301         du = (u1-u0) / (x1-x0);
302         dv = (v1-v0) / (y1-y0);
303
304         v = v0;
305
306         for (y=y0; y<=y1; y++ )                 {
307                 if ( f2i(v) != last_row )       {
308                         last_row = f2i(v);
309                         decode_row( source_bmp, last_row );
310                 }
311                 scale_row_asm_transparent( scale_rle_data, &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0], x1-x0+1, u0, du );
312                 v += dv;
313         }
314 }
315
316 #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (fixmuldiv((x)-(x0),(y1)-(y0),(x1)-(x0))+(y0))
317
318 // Scales bitmap, bp, into vertbuf[0] to vertbuf[1]
319 void scale_bitmap(grs_bitmap *bp, grs_point *vertbuf ,int orientation)
320 {
321         grs_bitmap * dbp = &grd_curcanv->cv_bitmap;
322         fix x0, y0, x1, y1;
323         fix u0, v0, u1, v1;
324         fix clipped_x0, clipped_y0, clipped_x1, clipped_y1;
325         fix clipped_u0, clipped_v0, clipped_u1, clipped_v1;
326         fix xmin, xmax, ymin, ymax;
327         int dx0, dy0, dx1, dy1;
328         int dtemp;
329         // Set initial variables....
330
331         x0 = vertbuf[0].x; y0 = vertbuf[0].y;
332         x1 = vertbuf[2].x; y1 = vertbuf[2].y;
333
334         xmin = 0; ymin = 0;
335         xmax = i2f(dbp->bm_w)-fl2f(.5); ymax = i2f(dbp->bm_h)-fl2f(.5);
336
337         u0 = i2f(0); v0 = i2f(0);
338         u1 = i2f(bp->bm_w-1); v1 = i2f(bp->bm_h-1);
339
340         // Check for obviously offscreen bitmaps...
341         if ( (y1<=y0) || (x1<=x0) ) return;
342         if ( (x1<0 ) || (x0>=xmax) ) return;
343         if ( (y1<0 ) || (y0>=ymax) ) return;
344
345         clipped_u0 = u0; clipped_v0 = v0;
346         clipped_u1 = u1; clipped_v1 = v1;
347
348         clipped_x0 = x0; clipped_y0 = y0;
349         clipped_x1 = x1; clipped_y1 = y1;
350
351         // Clip the left, moving u0 right as necessary
352         if ( x0 < xmin )        {
353                 clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1);
354                 clipped_x0 = xmin;
355         }
356
357         // Clip the right, moving u1 left as necessary
358         if ( x1 > xmax )        {
359                 clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1);
360                 clipped_x1 = xmax;
361         }
362
363         // Clip the top, moving v0 down as necessary
364         if ( y0 < ymin )        {
365                 clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1);
366                 clipped_y0 = ymin;
367         }
368
369         // Clip the bottom, moving v1 up as necessary
370         if ( y1 > ymax )        {
371                 clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1);
372                 clipped_y1 = ymax;
373         }
374         
375         dx0 = f2i(clipped_x0); dx1 = f2i(clipped_x1);
376         dy0 = f2i(clipped_y0); dy1 = f2i(clipped_y1);
377
378         if (dx1<=dx0) return;
379         if (dy1<=dy0) return;
380
381 //      Assert( dx0>=0 );
382 //      Assert( dy0>=0 );
383 //      Assert( dx1<dbp->bm_w );
384 //      Assert( dy1<dbp->bm_h );
385 //      Assert( f2i(u0)<=f2i(u1) );
386 //      Assert( f2i(v0)<=f2i(v1) );
387 //      Assert( f2i(u0)>=0 );
388 //      Assert( f2i(v0)>=0 );
389 //      Assert( u1<i2f(bp->bm_w) );
390 //      Assert( v1<i2f(bp->bm_h) );
391 //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) );
392
393         dtemp = f2i(clipped_u1)-f2i(clipped_u0);
394
395 #if 0
396         if ( bp->bm_flags & BM_FLAG_RLE )
397                 scale_bitmap_c_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
398         else
399                 scale_bitmap_c(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
400 #endif
401         if ( bp->bm_flags & BM_FLAG_RLE )       {
402                 if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) )
403                         scale_up_bitmap_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
404                 else
405                         scale_bitmap_c_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
406         } else {
407                 if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) )
408                         scale_up_bitmap(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
409                 else
410                         scale_bitmap_c(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1  );
411         }
412 }
413