these routines are in tmerge.c
[btb/d2x.git] / main / texmerge.c
1 /* $Id: texmerge.c,v 1.3 2002-09-04 22:47:25 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-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Routines to cache merged textures.
18  *
19  * Old Log:
20  * Revision 1.1  1995/05/16  15:31:36  allender
21  * Initial revision
22  *
23  * Revision 2.0  1995/02/27  11:31:08  john
24  * New version 2.0, which has no anonymous unions, builds with
25  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
26  *
27  * Revision 1.28  1995/01/14  19:16:56  john
28  * First version of new bitmap paging code.
29  *
30  * Revision 1.27  1994/12/14  18:21:58  yuan
31  * *** empty log message ***
32  *
33  * Revision 1.26  1994/12/13  09:50:08  john
34  * Added Asserts to stop if wall looks like door.
35  *
36  * Revision 1.25  1994/12/07  00:35:24  mike
37  * change how flat shading average color is computed for paste-ons.
38  *
39  * Revision 1.24  1994/11/19  15:20:29  mike
40  * rip out unused code and data
41  *
42  * Revision 1.23  1994/11/12  16:38:51  mike
43  * deal with avg_color in texture merging.
44  *
45  * Revision 1.22  1994/11/09  19:55:39  john
46  * Added full rle support with texture rle caching.
47  *
48  * Revision 1.21  1994/10/20  15:21:16  john
49  * Took out the texmerge caching.
50  *
51  * Revision 1.20  1994/10/10  19:00:57  john
52  * Made caching info print every 1000 frames.
53  *
54  * Revision 1.19  1994/10/10  18:41:21  john
55  * Printed out texture caching info.
56  *
57  * Revision 1.18  1994/08/11  18:59:02  mike
58  * Use new assembler version of merge functions.
59  *
60  * Revision 1.17  1994/06/09  12:13:14  john
61  * Changed selectors so that all bitmaps have a selector of
62  * 0, but inside the texture mapper they get a selector set.
63  *
64  * Revision 1.16  1994/05/14  17:15:15  matt
65  * Got rid of externs in source (non-header) files
66  *
67  * Revision 1.15  1994/05/09  17:21:09  john
68  * Took out mprintf with cache hits/misses.
69  *
70  * Revision 1.14  1994/05/05  12:55:07  john
71  * Made SuperTransparency work.
72  *
73  * Revision 1.13  1994/05/04  11:15:37  john
74  * Added Super Transparency
75  *
76  * Revision 1.12  1994/04/28  23:36:04  john
77  * Took out a debugging mprintf.
78  *
79  * Revision 1.11  1994/04/22  17:44:48  john
80  * Made top 2 bits of paste-ons pick the
81  * orientation of the bitmap.
82  *
83  * Revision 1.10  1994/03/31  12:05:51  matt
84  * Cleaned up includes
85  *
86  * Revision 1.9  1994/03/15  16:31:52  yuan
87  * Cleaned up bm-loading code.
88  * (And structures)
89  *
90  * Revision 1.8  1994/01/24  13:15:19  john
91  * Made caching work with pointers, not texture numbers,
92  * that way, the animated textures cache.
93  *
94  * Revision 1.7  1994/01/21  16:38:10  john
95  * Took out debug info.
96  *
97  * Revision 1.6  1994/01/21  16:28:43  john
98  * added warning to print cache hit/miss.
99  *
100  * Revision 1.5  1994/01/21  16:22:30  john
101  * Put in caching/
102  *
103  * Revision 1.4  1994/01/21  15:34:49  john
104  * *** empty log message ***
105  *
106  * Revision 1.3  1994/01/21  15:33:08  john
107  * *** empty log message ***
108  *
109  * Revision 1.2  1994/01/21  15:15:35  john
110  * Created new module texmerge, that merges textures together and
111  * caches the results.
112  *
113  * Revision 1.1  1994/01/21  14:55:29  john
114  * Initial revision
115  *
116  *
117  */
118
119 #ifdef HAVE_CONFIG_H
120 #include <conf.h>
121 #endif
122
123 #include <stdio.h>
124
125 #include "pa_enabl.h"                   //$$POLY_ACC
126 #include "gr.h"
127 #include "error.h"
128 #include "game.h"
129 #include "textures.h"
130 #include "mono.h"
131 #include "rle.h"
132 #include "piggy.h"
133
134 #if defined(POLY_ACC)
135 #include "poly_acc.h"
136 #endif
137
138 #ifdef OGL
139 #include "ogl_init.h"
140 #define MAX_NUM_CACHE_BITMAPS 200
141 #else
142 #define MAX_NUM_CACHE_BITMAPS 50
143 #endif
144
145 //static grs_bitmap * cache_bitmaps[MAX_NUM_CACHE_BITMAPS];                     
146
147 typedef struct  {
148         grs_bitmap * bitmap;
149         grs_bitmap * bottom_bmp;
150         grs_bitmap * top_bmp;
151         int             orient;
152         int             last_frame_used;
153 } TEXTURE_CACHE;
154
155 static TEXTURE_CACHE Cache[MAX_NUM_CACHE_BITMAPS];
156
157 static int num_cache_entries = 0;
158
159 static int cache_hits = 0;
160 static int cache_misses = 0;
161
162 void texmerge_close();
163 void merge_textures_super_xparent(int type, grs_bitmap *bottom_bmp, grs_bitmap *top_bmp,
164                                                                                          ubyte *dest_data);
165 void merge_textures_new(int type, grs_bitmap *bottom_bmp, grs_bitmap *top_bmp,
166                                                                 ubyte *dest_data);
167
168 #if defined(POLY_ACC)       // useful to all of D2 I think.
169 extern grs_bitmap * rle_get_id_sub( grs_bitmap * bmp );
170
171 //----------------------------------------------------------------------
172 // Given pointer to a bitmap returns a unique value that describes the bitmap.
173 // Returns 0xFFFFFFFF if this bitmap isn't a texmerge'd bitmap.
174 uint texmerge_get_unique_id( grs_bitmap * bmp )
175 {
176     int i,n;
177     uint tmp;
178     grs_bitmap * tmpbmp;
179     // Check in texmerge cache
180     for (i=0; i<num_cache_entries; i++ )    {
181         if ( (Cache[i].last_frame_used > -1) && (Cache[i].bitmap == bmp) )  {
182             tmp = (uint)Cache[i].orient<<30;
183             tmp |= ((uint)(Cache[i].top_bmp - GameBitmaps))<<16;
184             tmp |= (uint)(Cache[i].bottom_bmp - GameBitmaps);
185             return tmp;
186         }
187     }
188     // Check in rle cache
189     tmpbmp = rle_get_id_sub( bmp );
190     if ( tmpbmp )   {
191         return (uint)(tmpbmp-GameBitmaps);
192     }
193     // Must be a normal bitmap
194      return (uint)(bmp-GameBitmaps);
195 }
196 #endif
197
198 //----------------------------------------------------------------------
199
200 int texmerge_init(int num_cached_textures)
201 {
202         int i;
203
204         if ( num_cached_textures <= MAX_NUM_CACHE_BITMAPS )
205                 num_cache_entries = num_cached_textures;
206         else
207                 num_cache_entries = MAX_NUM_CACHE_BITMAPS;
208         
209         for (i=0; i<num_cache_entries; i++ )    {
210                         // Make temp tmap for use when combining
211                 Cache[i].bitmap = gr_create_bitmap( 64, 64 );
212
213                 //if (get_selector( Cache[i].bitmap->bm_data, 64*64,  &Cache[i].bitmap->bm_selector))
214                 //      Error( "ERROR ALLOCATING CACHE BITMAP'S SELECTORS!!!!" );
215
216                 Cache[i].last_frame_used = -1;
217                 Cache[i].top_bmp = NULL;
218                 Cache[i].bottom_bmp = NULL;
219                 Cache[i].orient = -1;
220         }
221         atexit( texmerge_close );
222
223         return 1;
224 }
225
226 void texmerge_flush()
227 {
228         int i;
229
230         for (i=0; i<num_cache_entries; i++ )    {
231                 Cache[i].last_frame_used = -1;
232                 Cache[i].top_bmp = NULL;
233                 Cache[i].bottom_bmp = NULL;
234                 Cache[i].orient = -1;
235         }
236 }
237
238
239 //-------------------------------------------------------------------------
240 void texmerge_close()
241 {
242         int i;
243
244         for (i=0; i<num_cache_entries; i++ )    {
245                 gr_free_bitmap( Cache[i].bitmap );
246                 Cache[i].bitmap = NULL;
247         }
248 }
249
250 //--unused-- int info_printed = 0;
251
252 grs_bitmap * texmerge_get_cached_bitmap( int tmap_bottom, int tmap_top )
253 {
254         grs_bitmap *bitmap_top, *bitmap_bottom;
255         int i, orient;
256         int lowest_frame_count;
257         int least_recently_used;
258
259 //      if ( ((FrameCount % 1000)==0) && ((cache_hits+cache_misses)>0) && (!info_printed) )     {
260 //              mprintf( 0, "Texmap caching:  %d hits, %d misses. (Missed=%d%%)\n", cache_hits, cache_misses, (cache_misses*100)/(cache_hits+cache_misses)  );
261 //              info_printed = 1;
262 //      } else {
263 //              info_printed = 0;
264 //      }
265
266         bitmap_top = &GameBitmaps[Textures[tmap_top&0x3FFF].index];
267         bitmap_bottom = &GameBitmaps[Textures[tmap_bottom].index];
268         
269         orient = ((tmap_top&0xC000)>>14) & 3;
270
271         least_recently_used = 0;
272         lowest_frame_count = Cache[0].last_frame_used;
273         
274         for (i=0; i<num_cache_entries; i++ )    {
275                 if ( (Cache[i].last_frame_used > -1) && (Cache[i].top_bmp==bitmap_top) && (Cache[i].bottom_bmp==bitmap_bottom) && (Cache[i].orient==orient ))   {
276                         cache_hits++;
277                         Cache[i].last_frame_used = FrameCount;
278                         return Cache[i].bitmap;
279                 }       
280                 if ( Cache[i].last_frame_used < lowest_frame_count )    {
281                         lowest_frame_count = Cache[i].last_frame_used;
282                         least_recently_used = i;
283                 }
284         }
285
286         //---- Page out the LRU bitmap;
287         cache_misses++;
288
289         // Make sure the bitmaps are paged in...
290 #ifdef PIGGY_USE_PAGING
291         piggy_page_flushed = 0;
292
293         PIGGY_PAGE_IN(Textures[tmap_top&0x3FFF]);
294         PIGGY_PAGE_IN(Textures[tmap_bottom]);
295         if (piggy_page_flushed) {
296                 // If cache got flushed, re-read 'em.
297                 piggy_page_flushed = 0;
298                 PIGGY_PAGE_IN(Textures[tmap_top&0x3FFF]);
299                 PIGGY_PAGE_IN(Textures[tmap_bottom]);
300         }
301         Assert( piggy_page_flushed == 0 );
302 #endif
303
304 #ifdef OGL
305         ogl_freebmtexture(Cache[least_recently_used].bitmap);
306 #endif
307
308
309         if (bitmap_top->bm_flags & BM_FLAG_SUPER_TRANSPARENT)   {
310                 merge_textures_super_xparent( orient, bitmap_bottom, bitmap_top, Cache[least_recently_used].bitmap->bm_data );
311                 Cache[least_recently_used].bitmap->bm_flags = BM_FLAG_TRANSPARENT;
312                 Cache[least_recently_used].bitmap->avg_color = bitmap_top->avg_color;
313         } else  {
314                 merge_textures_new( orient, bitmap_bottom, bitmap_top, Cache[least_recently_used].bitmap->bm_data );
315                 Cache[least_recently_used].bitmap->bm_flags = bitmap_bottom->bm_flags & (~BM_FLAG_RLE);
316                 Cache[least_recently_used].bitmap->avg_color = bitmap_bottom->avg_color;
317         }
318
319         Cache[least_recently_used].top_bmp = bitmap_top;
320         Cache[least_recently_used].bottom_bmp = bitmap_bottom;
321         Cache[least_recently_used].last_frame_used = FrameCount;
322         Cache[least_recently_used].orient = orient;
323
324         return Cache[least_recently_used].bitmap;
325 }
326
327 void merge_textures_new( int type, grs_bitmap * bottom_bmp, grs_bitmap * top_bmp, ubyte * dest_data )
328 {
329         ubyte * top_data, *bottom_data;
330
331         if ( top_bmp->bm_flags & BM_FLAG_RLE )
332                 top_bmp = rle_expand_texture(top_bmp);
333
334         if ( bottom_bmp->bm_flags & BM_FLAG_RLE )
335                 bottom_bmp = rle_expand_texture(bottom_bmp);
336
337 //      Assert( bottom_bmp != top_bmp );
338
339         top_data = top_bmp->bm_data;
340         bottom_data = bottom_bmp->bm_data;
341
342 //      Assert( bottom_data != top_data );
343
344         // mprintf( 0, "Type=%d\n", type );
345
346         switch( type )  {
347         case 0:
348                 // Normal
349
350                 gr_merge_textures( bottom_data, top_data, dest_data );
351                 break;
352         case 1:
353                 gr_merge_textures_1( bottom_data, top_data, dest_data );
354                 break;
355         case 2:
356                 gr_merge_textures_2( bottom_data, top_data, dest_data );
357                 break;
358         case 3:
359                 gr_merge_textures_3( bottom_data, top_data, dest_data );
360                 break;
361         }
362 }
363
364 void merge_textures_super_xparent( int type, grs_bitmap * bottom_bmp, grs_bitmap * top_bmp, ubyte * dest_data )
365 {
366         ubyte c;
367         int x,y;
368
369         ubyte * top_data, *bottom_data;
370
371         if ( top_bmp->bm_flags & BM_FLAG_RLE )
372                 top_bmp = rle_expand_texture(top_bmp);
373
374         if ( bottom_bmp->bm_flags & BM_FLAG_RLE )
375                 bottom_bmp = rle_expand_texture(bottom_bmp);
376
377 //      Assert( bottom_bmp != top_bmp );
378
379         top_data = top_bmp->bm_data;
380         bottom_data = bottom_bmp->bm_data;
381
382 //      Assert( bottom_data != top_data );
383
384         //mprintf( 0, "SuperX remapping type=%d\n", type );
385         //Int3();
386          
387         switch( type )  {
388                 case 0:
389                         // Normal
390                         for (y=0; y<64; y++ )
391                                 for (x=0; x<64; x++ )   {
392                                         c = top_data[ 64*y+x ];         
393                                         if (c==TRANSPARENCY_COLOR)
394                                                 c = bottom_data[ 64*y+x ];
395                                         else if (c==254)
396                                                 c = TRANSPARENCY_COLOR;
397                                         *dest_data++ = c;
398                                 }
399                         break;
400                 case 1:
401                         // 
402                         for (y=0; y<64; y++ )
403                                 for (x=0; x<64; x++ )   {
404                                         c = top_data[ 64*x+(63-y) ];            
405                                         if (c==TRANSPARENCY_COLOR)
406                                                 c = bottom_data[ 64*y+x ];
407                                         else if (c==254)
408                                                 c = TRANSPARENCY_COLOR;
409                                         *dest_data++ = c;
410                                 }
411                         break;
412                 case 2:
413                         // Normal
414                         for (y=0; y<64; y++ )
415                                 for (x=0; x<64; x++ )   {
416                                         c = top_data[ 64*(63-y)+(63-x) ];
417                                         if (c==TRANSPARENCY_COLOR)
418                                                 c = bottom_data[ 64*y+x ];
419                                         else if (c==254)
420                                                 c = TRANSPARENCY_COLOR;
421                                         *dest_data++ = c;
422                                 }
423                         break;
424                 case 3:
425                         // Normal
426                         for (y=0; y<64; y++ )
427                                 for (x=0; x<64; x++ )   {
428                                         c = top_data[ 64*(63-x)+y  ];
429                                         if (c==TRANSPARENCY_COLOR)
430                                                 c = bottom_data[ 64*y+x ];
431                                         else if (c==254)
432                                                 c = TRANSPARENCY_COLOR;
433                                         *dest_data++ = c;
434                                 }
435                         break;
436         }
437 }