Enable global structs for mine saving functions
[btb/d2x.git] / main / texmerge.c
1 /* $Id: texmerge.c,v 1.4 2004-08-28 23:17:45 schaffner 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-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Routines to cache merged textures.
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24
25 #include <stdio.h>
26
27 #include "pa_enabl.h"                   //$$POLY_ACC
28 #include "gr.h"
29 #include "error.h"
30 #include "game.h"
31 #include "textures.h"
32 #include "mono.h"
33 #include "rle.h"
34 #include "piggy.h"
35
36 #if defined(POLY_ACC)
37 #include "poly_acc.h"
38 #endif
39
40 #ifdef OGL
41 #include "ogl_init.h"
42 #define MAX_NUM_CACHE_BITMAPS 200
43 #else
44 #define MAX_NUM_CACHE_BITMAPS 50
45 #endif
46
47 //static grs_bitmap * cache_bitmaps[MAX_NUM_CACHE_BITMAPS];                     
48
49 typedef struct  {
50         grs_bitmap * bitmap;
51         grs_bitmap * bottom_bmp;
52         grs_bitmap * top_bmp;
53         int             orient;
54         int             last_frame_used;
55 } TEXTURE_CACHE;
56
57 static TEXTURE_CACHE Cache[MAX_NUM_CACHE_BITMAPS];
58
59 static int num_cache_entries = 0;
60
61 static int cache_hits = 0;
62 static int cache_misses = 0;
63
64 void texmerge_close();
65 void merge_textures_super_xparent(int type, grs_bitmap *bottom_bmp, grs_bitmap *top_bmp,
66                                                                                          ubyte *dest_data);
67 void merge_textures_new(int type, grs_bitmap *bottom_bmp, grs_bitmap *top_bmp,
68                                                                 ubyte *dest_data);
69
70 #if defined(POLY_ACC)       // useful to all of D2 I think.
71 extern grs_bitmap * rle_get_id_sub( grs_bitmap * bmp );
72
73 //----------------------------------------------------------------------
74 // Given pointer to a bitmap returns a unique value that describes the bitmap.
75 // Returns 0xFFFFFFFF if this bitmap isn't a texmerge'd bitmap.
76 uint texmerge_get_unique_id( grs_bitmap * bmp )
77 {
78     int i,n;
79     uint tmp;
80     grs_bitmap * tmpbmp;
81     // Check in texmerge cache
82     for (i=0; i<num_cache_entries; i++ )    {
83         if ( (Cache[i].last_frame_used > -1) && (Cache[i].bitmap == bmp) )  {
84             tmp = (uint)Cache[i].orient<<30;
85             tmp |= ((uint)(Cache[i].top_bmp - GameBitmaps))<<16;
86             tmp |= (uint)(Cache[i].bottom_bmp - GameBitmaps);
87             return tmp;
88         }
89     }
90     // Check in rle cache
91     tmpbmp = rle_get_id_sub( bmp );
92     if ( tmpbmp )   {
93         return (uint)(tmpbmp-GameBitmaps);
94     }
95     // Must be a normal bitmap
96      return (uint)(bmp-GameBitmaps);
97 }
98 #endif
99
100 //----------------------------------------------------------------------
101
102 int texmerge_init(int num_cached_textures)
103 {
104         int i;
105
106         if ( num_cached_textures <= MAX_NUM_CACHE_BITMAPS )
107                 num_cache_entries = num_cached_textures;
108         else
109                 num_cache_entries = MAX_NUM_CACHE_BITMAPS;
110         
111         for (i=0; i<num_cache_entries; i++ )    {
112                         // Make temp tmap for use when combining
113                 Cache[i].bitmap = gr_create_bitmap( 64, 64 );
114
115                 //if (get_selector( Cache[i].bitmap->bm_data, 64*64,  &Cache[i].bitmap->bm_selector))
116                 //      Error( "ERROR ALLOCATING CACHE BITMAP'S SELECTORS!!!!" );
117
118                 Cache[i].last_frame_used = -1;
119                 Cache[i].top_bmp = NULL;
120                 Cache[i].bottom_bmp = NULL;
121                 Cache[i].orient = -1;
122         }
123         atexit( texmerge_close );
124
125         return 1;
126 }
127
128 void texmerge_flush()
129 {
130         int i;
131
132         for (i=0; i<num_cache_entries; i++ )    {
133                 Cache[i].last_frame_used = -1;
134                 Cache[i].top_bmp = NULL;
135                 Cache[i].bottom_bmp = NULL;
136                 Cache[i].orient = -1;
137         }
138 }
139
140
141 //-------------------------------------------------------------------------
142 void texmerge_close()
143 {
144         int i;
145
146         for (i=0; i<num_cache_entries; i++ )    {
147                 gr_free_bitmap( Cache[i].bitmap );
148                 Cache[i].bitmap = NULL;
149         }
150 }
151
152 //--unused-- int info_printed = 0;
153
154 grs_bitmap * texmerge_get_cached_bitmap( int tmap_bottom, int tmap_top )
155 {
156         grs_bitmap *bitmap_top, *bitmap_bottom;
157         int i, orient;
158         int lowest_frame_count;
159         int least_recently_used;
160
161 //      if ( ((FrameCount % 1000)==0) && ((cache_hits+cache_misses)>0) && (!info_printed) )     {
162 //              mprintf( 0, "Texmap caching:  %d hits, %d misses. (Missed=%d%%)\n", cache_hits, cache_misses, (cache_misses*100)/(cache_hits+cache_misses)  );
163 //              info_printed = 1;
164 //      } else {
165 //              info_printed = 0;
166 //      }
167
168         bitmap_top = &GameBitmaps[Textures[tmap_top&0x3FFF].index];
169         bitmap_bottom = &GameBitmaps[Textures[tmap_bottom].index];
170         
171         orient = ((tmap_top&0xC000)>>14) & 3;
172
173         least_recently_used = 0;
174         lowest_frame_count = Cache[0].last_frame_used;
175         
176         for (i=0; i<num_cache_entries; i++ )    {
177                 if ( (Cache[i].last_frame_used > -1) && (Cache[i].top_bmp==bitmap_top) && (Cache[i].bottom_bmp==bitmap_bottom) && (Cache[i].orient==orient ))   {
178                         cache_hits++;
179                         Cache[i].last_frame_used = FrameCount;
180                         return Cache[i].bitmap;
181                 }       
182                 if ( Cache[i].last_frame_used < lowest_frame_count )    {
183                         lowest_frame_count = Cache[i].last_frame_used;
184                         least_recently_used = i;
185                 }
186         }
187
188         //---- Page out the LRU bitmap;
189         cache_misses++;
190
191         // Make sure the bitmaps are paged in...
192 #ifdef PIGGY_USE_PAGING
193         piggy_page_flushed = 0;
194
195         PIGGY_PAGE_IN(Textures[tmap_top&0x3FFF]);
196         PIGGY_PAGE_IN(Textures[tmap_bottom]);
197         if (piggy_page_flushed) {
198                 // If cache got flushed, re-read 'em.
199                 piggy_page_flushed = 0;
200                 PIGGY_PAGE_IN(Textures[tmap_top&0x3FFF]);
201                 PIGGY_PAGE_IN(Textures[tmap_bottom]);
202         }
203         Assert( piggy_page_flushed == 0 );
204 #endif
205
206 #ifdef OGL
207         ogl_freebmtexture(Cache[least_recently_used].bitmap);
208 #endif
209
210
211         if (bitmap_top->bm_flags & BM_FLAG_SUPER_TRANSPARENT)   {
212                 merge_textures_super_xparent( orient, bitmap_bottom, bitmap_top, Cache[least_recently_used].bitmap->bm_data );
213                 Cache[least_recently_used].bitmap->bm_flags = BM_FLAG_TRANSPARENT;
214                 Cache[least_recently_used].bitmap->avg_color = bitmap_top->avg_color;
215         } else  {
216                 merge_textures_new( orient, bitmap_bottom, bitmap_top, Cache[least_recently_used].bitmap->bm_data );
217                 Cache[least_recently_used].bitmap->bm_flags = bitmap_bottom->bm_flags & (~BM_FLAG_RLE);
218                 Cache[least_recently_used].bitmap->avg_color = bitmap_bottom->avg_color;
219         }
220
221         Cache[least_recently_used].top_bmp = bitmap_top;
222         Cache[least_recently_used].bottom_bmp = bitmap_bottom;
223         Cache[least_recently_used].last_frame_used = FrameCount;
224         Cache[least_recently_used].orient = orient;
225
226         return Cache[least_recently_used].bitmap;
227 }
228
229 void merge_textures_new( int type, grs_bitmap * bottom_bmp, grs_bitmap * top_bmp, ubyte * dest_data )
230 {
231         ubyte * top_data, *bottom_data;
232
233         if ( top_bmp->bm_flags & BM_FLAG_RLE )
234                 top_bmp = rle_expand_texture(top_bmp);
235
236         if ( bottom_bmp->bm_flags & BM_FLAG_RLE )
237                 bottom_bmp = rle_expand_texture(bottom_bmp);
238
239 //      Assert( bottom_bmp != top_bmp );
240
241         top_data = top_bmp->bm_data;
242         bottom_data = bottom_bmp->bm_data;
243
244 //      Assert( bottom_data != top_data );
245
246         // mprintf( 0, "Type=%d\n", type );
247
248         switch( type )  {
249         case 0:
250                 // Normal
251
252                 gr_merge_textures( bottom_data, top_data, dest_data );
253                 break;
254         case 1:
255                 gr_merge_textures_1( bottom_data, top_data, dest_data );
256                 break;
257         case 2:
258                 gr_merge_textures_2( bottom_data, top_data, dest_data );
259                 break;
260         case 3:
261                 gr_merge_textures_3( bottom_data, top_data, dest_data );
262                 break;
263         }
264 }
265
266 void merge_textures_super_xparent( int type, grs_bitmap * bottom_bmp, grs_bitmap * top_bmp, ubyte * dest_data )
267 {
268         ubyte c;
269         int x,y;
270
271         ubyte * top_data, *bottom_data;
272
273         if ( top_bmp->bm_flags & BM_FLAG_RLE )
274                 top_bmp = rle_expand_texture(top_bmp);
275
276         if ( bottom_bmp->bm_flags & BM_FLAG_RLE )
277                 bottom_bmp = rle_expand_texture(bottom_bmp);
278
279 //      Assert( bottom_bmp != top_bmp );
280
281         top_data = top_bmp->bm_data;
282         bottom_data = bottom_bmp->bm_data;
283
284 //      Assert( bottom_data != top_data );
285
286         //mprintf( 0, "SuperX remapping type=%d\n", type );
287         //Int3();
288          
289         switch( type )  {
290                 case 0:
291                         // Normal
292                         for (y=0; y<64; y++ )
293                                 for (x=0; x<64; x++ )   {
294                                         c = top_data[ 64*y+x ];         
295                                         if (c==TRANSPARENCY_COLOR)
296                                                 c = bottom_data[ 64*y+x ];
297                                         else if (c==254)
298                                                 c = TRANSPARENCY_COLOR;
299                                         *dest_data++ = c;
300                                 }
301                         break;
302                 case 1:
303                         // 
304                         for (y=0; y<64; y++ )
305                                 for (x=0; x<64; x++ )   {
306                                         c = top_data[ 64*x+(63-y) ];            
307                                         if (c==TRANSPARENCY_COLOR)
308                                                 c = bottom_data[ 64*y+x ];
309                                         else if (c==254)
310                                                 c = TRANSPARENCY_COLOR;
311                                         *dest_data++ = c;
312                                 }
313                         break;
314                 case 2:
315                         // Normal
316                         for (y=0; y<64; y++ )
317                                 for (x=0; x<64; x++ )   {
318                                         c = top_data[ 64*(63-y)+(63-x) ];
319                                         if (c==TRANSPARENCY_COLOR)
320                                                 c = bottom_data[ 64*y+x ];
321                                         else if (c==254)
322                                                 c = TRANSPARENCY_COLOR;
323                                         *dest_data++ = c;
324                                 }
325                         break;
326                 case 3:
327                         // Normal
328                         for (y=0; y<64; y++ )
329                                 for (x=0; x<64; x++ )   {
330                                         c = top_data[ 64*(63-x)+y  ];
331                                         if (c==TRANSPARENCY_COLOR)
332                                                 c = bottom_data[ 64*y+x ];
333                                         else if (c==254)
334                                                 c = TRANSPARENCY_COLOR;
335                                         *dest_data++ = c;
336                                 }
337                         break;
338         }
339 }