more stuff from d2src
[btb/d2x.git] / 2d / bitmap.c
1 /* $Id: bitmap.c,v 1.4 2002-09-05 07:55:20 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 <stdio.h>
21
22 #include "u_mem.h"
23
24
25 #include "gr.h"
26 #include "grdef.h"
27 #include "u_dpmi.h"
28 #include "error.h"
29
30 #if defined(POLY_ACC)
31 #include "poly_acc.h"
32 #endif
33
34 #ifdef OGL
35 #include "ogl_init.h"
36 #endif
37
38 void gr_set_bitmap_data (grs_bitmap *bm, unsigned char *data)
39 {
40 #ifdef OGL
41 //      if (bm->bm_data!=data)
42                 ogl_freebmtexture(bm);
43 #endif
44         bm->bm_data = data;
45 #ifdef D1XD3D
46         Assert (bm->iMagic == BM_MAGIC_NUMBER);
47         Win32_SetTextureBits (bm, data, bm->bm_flags & BM_FLAG_RLE);
48 #endif
49 }
50
51 grs_bitmap *gr_create_bitmap(int w, int h )
52 {
53         return gr_create_bitmap_raw (w, h, d_malloc(w * h));
54 }
55
56 grs_bitmap *gr_create_bitmap_raw(int w, int h, unsigned char * raw_data )
57 {
58     grs_bitmap *new;
59
60     new = (grs_bitmap *)d_malloc( sizeof(grs_bitmap) );
61         gr_init_bitmap (new, 0, 0, 0, w, h, w, raw_data);
62
63     return new;
64 }
65
66
67 #if defined(POLY_ACC)
68 //
69 //  Creates a bitmap of the requested size and type.
70 //    w, and h are in pixels.
71 //    type is a BM_... and is used to set the rowsize.
72 //    if data is NULL, memory is allocated, otherwise data is used for bm_data.
73 //
74 //  This function is used only by the polygon accelerator code to handle the mixture of 15bit and
75 //  8bit bitmaps.
76 //
77 grs_bitmap *gr_create_bitmap2(int w, int h, int type, void *data )
78 {
79         grs_bitmap *new;
80
81         new = (grs_bitmap *)malloc( sizeof(grs_bitmap) );
82         new->bm_x = 0;
83         new->bm_y = 0;
84         new->bm_w = w;
85         new->bm_h = h;
86         new->bm_flags = 0;
87     new->bm_type = type;
88     switch(type)
89     {
90         case BM_LINEAR:     new->bm_rowsize = w;            break;
91         case BM_LINEAR15:   new->bm_rowsize = w*PA_BPP;     break;
92         default: Int3();    // unsupported type.
93     }
94     if(data)
95         new->bm_data = data;
96     else
97         new->bm_data = malloc(new->bm_rowsize * new->bm_h);
98         new->bm_handle = 0;
99
100         return new;
101 }
102 #endif
103
104 void gr_init_bitmap( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline, unsigned char * data ) // TODO: virtualize
105 {
106 #ifdef D1XD3D
107         Assert (bm->iMagic != BM_MAGIC_NUMBER || bm->pvSurface == NULL);
108 #endif
109
110         bm->bm_x = x;
111         bm->bm_y = y;
112         bm->bm_w = w;
113         bm->bm_h = h;
114         bm->bm_flags = 0;
115         bm->bm_type = mode;
116         bm->bm_rowsize = bytesperline;
117
118         bm->bm_data = NULL;
119 #ifdef D1XD3D
120         bm->iMagic = BM_MAGIC_NUMBER;
121         bm->pvSurface = NULL;
122 #endif
123
124 #ifdef D1XD3D
125         Win32_CreateTexture (bm);
126 #endif
127 #ifdef OGL
128         bm->bm_parent=NULL;bm->gltexture=NULL;
129 #endif
130
131 //      if (data != 0)
132                 gr_set_bitmap_data (bm, data);
133 /*
134         else
135                 gr_set_bitmap_data (bm, d_malloc (w * h));
136 */
137
138 #ifdef BITMAP_SELECTOR
139         bm->bm_selector = 0;
140 #endif
141 }
142
143 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline)
144 {
145         gr_init_bitmap(bm, mode, x, y, w, h, bytesperline, 0);
146         gr_set_bitmap_data(bm, d_malloc(w * h));
147 }
148
149 void gr_init_bitmap_data (grs_bitmap *bm) // TODO: virtulize
150 {
151         bm->bm_data = NULL;
152 #ifdef D1XD3D
153         Assert (bm->iMagic != BM_MAGIC_NUMBER);
154         bm->iMagic = BM_MAGIC_NUMBER;
155         bm->pvSurface = NULL;
156 #endif
157 #ifdef OGL
158 //      ogl_freebmtexture(bm);//not what we want here.
159         bm->bm_parent=NULL;bm->gltexture=NULL;
160 #endif
161 }
162
163 grs_bitmap *gr_create_sub_bitmap(grs_bitmap *bm, int x, int y, int w, int h )
164 {
165     grs_bitmap *new;
166
167     new = (grs_bitmap *)d_malloc( sizeof(grs_bitmap) );
168         gr_init_sub_bitmap (new, bm, x, y, w, h);
169
170         return new;
171 }
172
173 void gr_free_bitmap(grs_bitmap *bm )
174 {
175         gr_free_bitmap_data (bm);
176         if (bm!=NULL)
177                 d_free(bm);
178 }
179
180 void gr_free_sub_bitmap(grs_bitmap *bm )
181 {
182         if (bm!=NULL)
183         {
184 #ifdef D1XD3D
185                 bm->iMagic = 0;
186 #endif
187                 d_free(bm);
188         }
189 }
190
191
192 void gr_free_bitmap_data (grs_bitmap *bm) // TODO: virtulize
193 {
194 #ifdef D1XD3D
195         Assert (bm->iMagic == BM_MAGIC_NUMBER);
196
197         Win32_FreeTexture (bm);
198         bm->iMagic = 0;
199         if (bm->bm_data == BM_D3D_RENDER)
200                 bm->bm_data = NULL;
201 #endif
202 #ifdef OGL
203         ogl_freebmtexture(bm);
204 #endif
205         if (bm->bm_data != NULL)
206                 d_free (bm->bm_data);
207         bm->bm_data = NULL;
208 }
209
210 void gr_init_sub_bitmap (grs_bitmap *bm, grs_bitmap *bmParent, int x, int y, int w, int h )     // TODO: virtualize
211 {
212         bm->bm_x = x + bmParent->bm_x;
213         bm->bm_y = y + bmParent->bm_y;
214         bm->bm_w = w;
215         bm->bm_h = h;
216         bm->bm_flags = bmParent->bm_flags;
217         bm->bm_type = bmParent->bm_type;
218         bm->bm_rowsize = bmParent->bm_rowsize;
219
220 #ifdef OGL
221         bm->gltexture=bmParent->gltexture;
222         bm->bm_parent=bmParent;
223 #endif
224 #ifdef D1XD3D
225         Assert (bmParent->iMagic == BM_MAGIC_NUMBER);
226         bm->iMagic = BM_MAGIC_NUMBER;
227         bm->pvSurface = bmParent->pvSurface;
228         if (bm->bm_type == BM_DIRECTX)
229         {
230                 bm->bm_data = bmParent->bm_data;
231         }
232         else
233 #endif
234         {
235                 bm->bm_data = bmParent->bm_data+(unsigned int)((y*bmParent->bm_rowsize)+x);
236         }
237
238 }
239
240 void decode_data_asm(ubyte *data, int num_pixels, ubyte * colormap, int * count );
241
242 #if !defined(NO_ASM) && defined(__WATCOMC__)
243
244 #pragma aux decode_data_asm parm [esi] [ecx] [edi] [ebx] modify exact [esi edi eax ebx ecx] = \
245 "again_ddn:"                                                    \
246         "xor    eax,eax"                                \
247         "mov    al,[esi]"                       \
248         "inc    dword ptr [ebx+eax*4]"          \
249         "mov    al,[edi+eax]"           \
250         "mov    [esi],al"                       \
251         "inc    esi"                                    \
252         "dec    ecx"                                    \
253         "jne    again_ddn"
254
255 #elif !defined(NO_ASM) && defined(__GNUC__)
256
257 inline void decode_data_asm(ubyte *data, int num_pixels, ubyte * colormap, int * count ) {
258         int dummy[4];
259    __asm__ __volatile__ (
260     "xorl   %%eax,%%eax;"
261 "0:;"
262     "movb   (%%esi), %%al;"
263     "incl   (%%ebx, %%eax, 4);"
264     "movb   (%%edi, %%eax), %%al;"
265     "movb   %%al, (%%esi);"
266     "incl   %%esi;"
267     "decl   %%ecx;"
268     "jne    0b"
269     : "=S" (dummy[0]), "=c" (dummy[1]), "=D" (dummy[2]), "=b" (dummy[3])
270         : "0" (data), "1" (num_pixels), "2" (colormap), "3" (count)
271         : "%eax");
272 }
273
274 #elif !defined(NO_ASM) && defined(_MSC_VER)
275
276 __inline void decode_data_asm(ubyte *data, int num_pixels, ubyte * colormap, int * count )
277 {
278   __asm {
279         mov esi,[data]
280         mov ecx,[num_pixels]
281         mov edi,[colormap]
282         mov ebx,[count]
283 again_ddn:
284         xor eax,eax
285         mov al,[esi]
286         inc dword ptr [ebx+eax*4]
287         mov al,[edi+eax]
288         mov [esi],al
289         inc esi
290         dec ecx
291         jne again_ddn
292   }
293 }
294
295 #else // NO_ASM or unknown compiler
296
297 void decode_data_asm(ubyte *data, int num_pixels, ubyte *colormap, int *count)
298 {
299         int i;
300         ubyte mapped;
301
302         for (i = 0; i < num_pixels; i++) {
303                 count[*data]++;
304                 mapped = *data;
305                 *data = colormap[mapped];
306                 data++;
307         }
308 }
309
310 #endif
311
312 void gr_set_bitmap_flags (grs_bitmap *pbm, int flags)
313 {
314 #ifdef D1XD3D
315         Assert (pbm->iMagic == BM_MAGIC_NUMBER);
316
317         if (pbm->pvSurface)
318         {
319                 if ((flags & BM_FLAG_TRANSPARENT) != (pbm->bm_flags & BM_FLAG_TRANSPARENT))
320                 {
321                         Win32_SetTransparent (pbm->pvSurface, flags & BM_FLAG_TRANSPARENT);
322                 }
323         }
324 #endif
325         pbm->bm_flags = flags;
326 }
327
328 void gr_set_transparent (grs_bitmap *pbm, int bTransparent)
329 {
330         if (bTransparent)
331         {
332                 gr_set_bitmap_flags (pbm, pbm->bm_flags | BM_FLAG_TRANSPARENT);
333         }
334         else
335         {
336                 gr_set_bitmap_flags (pbm, pbm->bm_flags & ~BM_FLAG_TRANSPARENT);
337         }
338 }
339
340 void gr_set_super_transparent (grs_bitmap *pbm, int bTransparent)
341 {
342         if (bTransparent)
343         {
344                 gr_set_bitmap_flags (pbm, pbm->bm_flags & ~BM_FLAG_SUPER_TRANSPARENT);
345         }
346         else
347         {
348                 gr_set_bitmap_flags (pbm, pbm->bm_flags | BM_FLAG_SUPER_TRANSPARENT);
349         }
350 }
351
352 void build_colormap_good( ubyte * palette, ubyte * colormap, int * freq )
353 {
354         int i, r, g, b;
355
356         for (i=0; i<256; i++ )  {
357                 r = *palette++;
358                 g = *palette++;
359                 b = *palette++;
360                 *colormap++ = gr_find_closest_color( r, g, b );
361                 *freq++ = 0;
362         }
363 }
364
365 void gr_remap_bitmap( grs_bitmap * bmp, ubyte * palette, int transparent_color, int super_transparent_color )
366 {
367         ubyte colormap[256];
368         int freq[256];
369
370         if (bmp->bm_type != BM_LINEAR)
371                 return;  //can't do it
372
373         // This should be build_colormap_asm, but we're not using invert table, so...
374         build_colormap_good( palette, colormap, freq );
375
376         if ( (super_transparent_color>=0) && (super_transparent_color<=255))
377                 colormap[super_transparent_color] = 254;
378
379         if ( (transparent_color>=0) && (transparent_color<=255))
380                 colormap[transparent_color] = TRANSPARENCY_COLOR;
381
382         decode_data_asm(bmp->bm_data, bmp->bm_w * bmp->bm_h, colormap, freq );
383
384         if ( (transparent_color>=0) && (transparent_color<=255) && (freq[transparent_color]>0) )
385                 gr_set_transparent (bmp, 1);
386
387         if ( (super_transparent_color>=0) && (super_transparent_color<=255) && (freq[super_transparent_color]>0) )
388                 gr_set_super_transparent (bmp, 0);
389 }
390
391 void gr_remap_bitmap_good( grs_bitmap * bmp, ubyte * palette, int transparent_color, int super_transparent_color )
392 {
393         ubyte colormap[256];
394         int freq[256];
395         build_colormap_good( palette, colormap, freq );
396
397         if ( (super_transparent_color>=0) && (super_transparent_color<=255))
398                 colormap[super_transparent_color] = 254;
399
400         if ( (transparent_color>=0) && (transparent_color<=255))
401                 colormap[transparent_color] = TRANSPARENCY_COLOR;
402
403         if (bmp->bm_w == bmp->bm_rowsize)
404                 decode_data_asm(bmp->bm_data, bmp->bm_w * bmp->bm_h, colormap, freq );
405         else {
406                 int y;
407                 ubyte *p = bmp->bm_data;
408                 for (y=0;y<bmp->bm_h;y++,p+=bmp->bm_rowsize)
409                         decode_data_asm(p, bmp->bm_w, colormap, freq );
410         }
411
412         if ( (transparent_color>=0) && (transparent_color<=255) && (freq[transparent_color]>0) )
413                 gr_set_transparent (bmp, 1);
414
415         if ( (super_transparent_color>=0) && (super_transparent_color<=255) && (freq[super_transparent_color]>0) )
416                 gr_set_super_transparent (bmp, 1);
417 }
418
419 #ifdef BITMAP_SELECTOR
420 int gr_bitmap_assign_selector( grs_bitmap * bmp )
421 {
422         if (!dpmi_allocate_selector( bmp->bm_data, bmp->bm_w*bmp->bm_h, &bmp->bm_selector )) {
423                 bmp->bm_selector = 0;
424                 return 1;
425         }
426         return 0;
427 }
428 #endif
429
430 void gr_bitmap_check_transparency( grs_bitmap * bmp )
431 {
432         int x, y;
433         ubyte * data;
434
435         data = bmp->bm_data;
436
437         for (y=0; y<bmp->bm_h; y++ )    {
438                 for (x=0; x<bmp->bm_w; x++ )    {
439                         if (*data++ == TRANSPARENCY_COLOR )     {
440                                 gr_set_transparent (bmp, 1);
441                                 return;
442                         }
443                 }
444                 data += bmp->bm_rowsize - bmp->bm_w;
445         }
446
447         bmp->bm_flags = 0;
448
449 }