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