]> icculus.org git repositories - taylor/freespace2.git/blob - src/bmpman/bmpman.cpp
finished cfilesystem.
[taylor/freespace2.git] / src / bmpman / bmpman.cpp
1 /*
2  * $Logfile: /Freespace2/code/Bmpman/BmpMan.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Code to load and manage all bitmaps for the game
8  *
9  * $Log$
10  * Revision 1.8  2002/06/05 04:03:32  relnev
11  * finished cfilesystem.
12  *
13  * removed some old code.
14  *
15  * fixed mouse save off-by-one.
16  *
17  * sound cleanups.
18  *
19  * Revision 1.7  2002/06/03 09:25:37  relnev
20  * implement mouse cursor and screen save/restore
21  *
22  * Revision 1.6  2002/05/30 23:07:08  relnev
23  * shh
24  *
25  * Revision 1.5  2002/05/30 21:44:48  relnev
26  * implemented some missing texture stuff.
27  *
28  * enable bitmap polys for opengl.
29  *
30  * work around greenness in bitmaps.
31  *
32  * Revision 1.4  2002/05/28 17:03:29  theoddone33
33  * fs2 gets to the main game loop now
34  *
35  * Revision 1.3  2002/05/28 08:52:03  relnev
36  * implemented two assembly stubs.
37  *
38  * cleaned up a few warnings.
39  *
40  * added a little demo hackery to make it progress a little farther.
41  *
42  * Revision 1.2  2002/05/07 03:16:43  theoddone33
43  * The Great Newline Fix
44  *
45  * Revision 1.1.1.1  2002/05/03 03:28:08  root
46  * Initial import.
47  *
48  * 
49  * 37    9/13/99 11:26p Andsager
50  * Add debug code to check for poorly sized anis
51  * 
52  * 36    9/05/99 11:19p Dave
53  * Made d3d texture cache much more safe. Fixed training scoring bug where
54  * it would backout scores without ever having applied them in the first
55  * place.
56  * 
57  * 35    8/20/99 2:09p Dave
58  * PXO banner cycling.
59  * 
60  * 34    8/10/99 6:54p Dave
61  * Mad optimizations. Added paging to the nebula effect.
62  * 
63  * 33    8/06/99 1:52p Dave
64  * Bumped up MAX_BITMAPS for the demo.
65  * 
66  * 32    8/02/99 1:49p Dave
67  * Fixed low-mem animation problem. Whee!
68  * 
69  * 31    7/16/99 1:49p Dave
70  * 8 bit aabitmaps. yay.
71  * 
72  * 30    7/13/99 1:15p Dave
73  * 32 bit support. Whee!
74  * 
75  * 29    6/29/99 10:35a Dave
76  * Interface polygon bitmaps! Whee!
77  * 
78  * 28    6/16/99 4:06p Dave
79  * New pilot info popup. Added new draw-bitmap-as-poly function.
80  * 
81  * 27    5/05/99 9:02p Dave
82  * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
83  * rotations, tweaked values, made bitmap selection more random). Fixed
84  * D3D beam weapon clipping problem. Added D3d frame dumping.
85  * 
86  * 26    4/27/99 12:16a Dave
87  * Fixed beam weapon muzzle glow problem. Fixed premature timeout on the
88  * pxo server list screen. Fixed secondary firing for hosts on a
89  * standalone. Fixed wacky multiplayer weapon "shuddering" problem.
90  * 
91  * 25    4/09/99 2:21p Dave
92  * Multiplayer beta stuff. CD checking.
93  * 
94  * 24    4/08/99 10:42a Johnson
95  * Don't try to swizzle a texture to transparent in Fred.
96  * 
97  * 23    3/31/99 8:24p Dave
98  * Beefed up all kinds of stuff, incluging beam weapons, nebula effects
99  * and background nebulae. Added per-ship non-dimming pixel colors.
100  * 
101  * 22    3/20/99 3:46p Dave
102  * Added support for model-based background nebulae. Added 3 new
103  * sexpressions.
104  * 
105  * 21    2/11/99 3:08p Dave
106  * PXO refresh button. Very preliminary squad war support.
107  * 
108  * 20    2/08/99 5:07p Dave
109  * FS2 chat server support. FS2 specific validated missions.
110  * 
111  * 19    2/05/99 12:52p Dave
112  * Fixed Glide nondarkening textures.
113  * 
114  * 18    2/04/99 6:29p Dave
115  * First full working rev of FS2 PXO support.  Fixed Glide lighting
116  * problems.
117  * 
118  * 17    2/03/99 11:44a Dave
119  * Fixed d3d transparent textures.
120  * 
121  * 16    1/15/99 11:29a Neilk
122  * Fixed D3D screen/texture pixel formatting problem. 
123  * 
124  * 15    1/14/99 12:48a Dave
125  * Todo list bug fixes. Made a pass at putting briefing icons back into
126  * FRED. Sort of works :(
127  * 
128  * 14    1/12/99 12:53a Dave
129  * More work on beam weapons - made collision detection very efficient -
130  * collide against all object types properly - made 3 movement types
131  * smooth. Put in test code to check for possible non-darkening pixels on
132  * object textures.
133  * 
134  * 13    1/08/99 2:08p Dave
135  * Fixed software rendering for pofview. Super early support for AWACS and
136  * beam weapons.
137  * 
138  * 12    1/06/99 2:24p Dave
139  * Stubs and release build fixes.
140  * 
141  * 11    12/14/98 4:01p Dave
142  * Got multi_data stuff working well with new xfer stuff. 
143  * 
144  * 10    12/06/98 2:36p Dave
145  * Drastically improved nebula fogging.
146  * 
147  * 9     12/01/98 5:53p Dave
148  * Simplified the way pixel data is swizzled. Fixed tga bitmaps to work
149  * properly in D3D and Glide.
150  * 
151  * 8     12/01/98 4:46p Dave
152  * Put in targa bitmap support (16 bit).
153  * 
154  * 7     12/01/98 10:32a Johnson
155  * Fixed direct3d font problems. Fixed sun bitmap problem. Fixed direct3d
156  * starfield problem.
157  * 
158  * 6     12/01/98 8:06a Dave
159  * Temporary checkin to fix some texture transparency problems in d3d.
160  * 
161  * 5     11/30/98 5:31p Dave
162  * Fixed up Fred support for software mode.
163  * 
164  * 4     11/30/98 1:07p Dave
165  * 16 bit conversion, first run.
166  * 
167  * 3     10/22/98 6:14p Dave
168  * Optimized some #includes in Anim folder. Put in the beginnings of
169  * parse/localization support for externalized strings and tstrings.tbl
170  * 
171  * 2     10/07/98 10:52a Dave
172  * Initial checkin.
173  * 
174  * 1     10/07/98 10:48a Dave
175  * 
176  * 106   5/23/98 4:43p John
177  * Took out debugging sleep
178  * 
179  * 105   5/23/98 4:14p John
180  * Added code to preload textures to video card for AGP.   Added in code
181  * to page in some bitmaps that weren't getting paged in at level start.
182  * 
183  * 104   5/20/98 12:59p John
184  * Turned optimizations on for debug builds.   Also turning on automatic
185  * function inlining.  Turned off the unreachable code warning.
186  * 
187  * 103   5/20/98 10:20a Hoffoss
188  * Fixed warning in the code.
189  * 
190  * 102   5/19/98 3:45p John
191  * fixed bug causing lowmem to drop half of the frames. Also halved fps
192  * during lowmem.
193  * 
194  * 101   5/14/98 3:38p John
195  * Added in more non-darkening colors for Adam.  Had to fix some bugs in
196  * BmpMan and Ani stuff to get this to work.
197  * 
198  * 100   4/22/98 9:13p John
199  * Added code to replace frames of animations in vram if so desired.
200  * 
201  * 99    4/17/98 6:56a John
202  * Fixed bug where RLE'd user bitmaps caused data to not get freed.
203  * (Turned off RLE for use bitmaps).   Made lossy animations reduce
204  * resolution by a factor of 2 in low memory conditions.
205  * 
206  * 98    4/16/98 6:31p Hoffoss
207  * Added function to get filename of a bitmap handle, which we don't have
208  * yet and I need.
209  * 
210  * 97    4/01/98 9:27p John
211  * Fixed debug info in bmpman.
212  * 
213  * 96    4/01/98 5:34p John
214  * Made only the used POFs page in for a level.   Reduced some interp
215  * arrays.    Made custom detail level work differently.
216  * 
217  * 95    3/31/98 9:55a Lawrance
218  * JOHN: get xparency working for user bitmaps
219  * 
220  * 94    3/30/98 4:02p John
221  * Made machines with < 32 MB of RAM use every other frame of certain
222  * bitmaps.   Put in code to keep track of how much RAM we've malloc'd.
223  * 
224  * 93    3/29/98 4:05p John
225  * New paging code that loads everything necessary at level startup.
226  * 
227  * 92    3/27/98 11:20a John
228  * commented back in some debug code.
229  * 
230  * 91    3/26/98 5:21p John
231  * Added new code to preload all bitmaps at the start of a level.
232  * Commented it out, though.
233  * 
234  * 90    3/26/98 4:56p Jasen
235  * AL: Allow find_block_of() to allocate a series of bitmaps from index 0
236  * 
237  * 89    3/26/98 10:21a John
238  * Made no palette-mapped bitmaps use 0,255,0 as transparent.
239  * 
240  * 88    3/24/98 5:39p John
241  * Added debug code to show bitmap fragmentation.  Made user bitmaps
242  * allocate from top of array.
243  * 
244  * 87    3/22/98 3:28p John
245  * Added in stippled alpha for lower details.  Made medium detail use
246  * engine glow.
247  * 
248  * 86    3/11/98 1:55p John
249  * Fixed warnings
250  * 
251  * 85    3/06/98 4:09p John
252  * Changed the way we do bitmap RLE'ing... this speds up HUD bitmaps by
253  * about 2x
254  * 
255  * 84    3/02/98 6:00p John
256  * Moved MAX_BITMAPS into BmpMan.h so the stuff in the graphics code that
257  * is dependent on it won't break if it changes.   Made ModelCache slots
258  * be equal to MAX_OBJECTS which is what it is.
259  * 
260  * 83    3/02/98 9:51a John
261  * Added code to print the number of bitmap slots in use between levels.
262  * 
263  * 82    2/16/98 3:54p John
264  * Changed a bunch of mprintfs to catagorize to BmpInfo
265  * 
266  * 81    2/13/98 5:00p John
267  * Made user bitmaps not get wrote to level cache file.
268  * 
269  * 80    2/06/98 8:25p John
270  * Added code for new bitmaps since last frame
271  * 
272  * 79    2/06/98 8:10p John
273  * Added code to show amout of texture usage each frame.
274  * 
275  * 78    2/05/98 9:21p John
276  * Some new Direct3D code.   Added code to monitor a ton of stuff in the
277  * game.
278  * 
279  * 77    1/29/98 11:48a John
280  * Added new counter measure rendering as model code.   Made weapons be
281  * able to have impact explosion.
282  * 
283  * 76    1/28/98 6:19p Dave
284  * Reduced standalone memory usage ~8 megs. Put in support for handling
285  * multiplayer submenu handling for endgame, etc.
286  * 
287  * 75    1/17/98 12:55p John
288  * Fixed bug that I just created that loaded all ani frames.
289  * 
290  * 74    1/17/98 12:33p John
291  * Made the game_busy function be called a constant amount of times per
292  * level load, making the bar prediction easier.
293  * 
294  * 73    1/17/98 12:14p John
295  * Added loading... bar to freespace.
296  * 
297  * 72    1/11/98 3:20p John
298  * Made so that if no .clt exists, it will load all the bitmaps
299  * 
300  * 71    1/11/98 3:06p John
301  * Made bitmap loading stop when cache gets full.
302  * 
303  * 70    1/11/98 2:45p John
304  * Changed .lst to .clt
305  * 
306  * 69    1/11/98 2:14p John
307  * Changed a lot of stuff that had to do with bitmap loading.   Made cfile
308  * not do callbacks, I put that in global code.   Made only bitmaps that
309  * need to load for a level load.
310  * 
311  * 67    1/09/98 4:07p John
312  * Made all bitmap functions return a bitmap "Handle" not number.  This
313  * helps to find bm_release errors.
314  * 
315  * 66    1/09/98 1:38p John
316  * Fixed some bugs from previous comment
317  * 
318  * 65    1/09/98 1:32p John
319  * Added some debugging code to track down a weird error.  Namely I fill
320  * in the be structure with bogus values when someone frees it.
321  * 
322  * 64    12/28/97 2:00p John
323  * put in another assert checking for invalid lock/unlock sequencing
324  * 
325  * 63    12/24/97 2:02p John
326  * Changed palette translation to be a little faster for unoptimized
327  * builds
328  * 
329  * 62    12/18/97 8:59p Dave
330  * Finished putting in basic support for weapon select and ship select in
331  * multiplayer.
332  * 
333  * 61    12/15/97 10:27p John
334  * fixed bug where 2 bm_loads of same file both open the header.
335  * 
336  * 60    12/08/97 2:17p John
337  * fixed bug with bmpman and cf_callback.
338  * made cf_callback in Freespace set small font back when done.
339  * 
340  * 59    12/03/97 5:01p Lawrance
341  * bump up MAX_BITMAPS to 1500.  People have reached 1000 bitmaps while
342  * playing multiple missions.
343  * 
344  * 58    12/02/97 3:59p John
345  * Added first rev of thruster glow, along with variable levels of
346  * translucency, which retquired some restructing of palman.
347  * 
348  * 57    11/30/97 3:57p John
349  * Made fixed 32-bpp translucency.  Made BmpMan always map translucent
350  * color into 255 even if you aren't supposed to remap and make it's
351  * palette black.
352  * 
353  * 56    10/05/97 10:39a John
354  * fixed bug with palette on unmapped bitmaps.  Made unmapped bitmaps get
355  * marked with xparent.
356  * 
357  * 55    9/23/97 11:46a Lawrance
358  * fixed bug with rle'ing with spans get big
359  * 
360  * 54    9/23/97 10:45a John
361  * made so you can tell bitblt code to rle a bitmap by passing flag to
362  * gr_set_bitmap
363  * 
364  * 53    9/19/97 10:18a John
365  * fixed bug with aa animations being re-rle'd every 
366  * frame.
367  * 
368  * 
369  * 52    9/09/97 10:08a Sandeep
370  * Fixed Compiler Level 4 warnings
371  * 
372  * 51    9/08/97 2:02p John
373  * fixed typo in nprintf
374  * 
375  * 50    9/08/97 1:56p John
376  * fixed some memory housekeeping bugs 
377  * 
378  * 49    9/03/97 4:19p John
379  * changed bmpman to only accept ani and pcx's.  made passing .pcx or .ani
380  * to bm_load functions not needed.   Made bmpman keep track of palettes
381  * for bitmaps not mapped into game palettes.
382  * 
383  * 48    8/29/97 7:35p Lawrance
384  * check if .ani animation is already loaded in bm_load_animation()
385  * 
386  * 47    8/25/97 11:14p Lawrance
387  * added support for .ani files in bm_load_animation()
388  * 
389  * 46    8/17/97 2:42p Lawrance
390  * only flag PCX files as xparent if they have xparent pixels in them
391  * 
392  * 45    8/15/97 9:57a Lawrance
393  * support multiple xparent entries for PCX files
394  * 
395  * 44    8/05/97 10:18a Lawrance
396  * my_rand() being used temporarily instead of rand()
397  * 
398  * 43    8/01/97 4:30p John
399  * 
400  * 42    7/29/97 8:34a John
401  * took out png stuff
402  * 
403  * 41    7/18/97 3:27p Lawrance
404  * have pcx files use (0,255,0) for transparency
405  * 
406  * 40    7/16/97 3:07p John
407  * 
408  * 39    7/10/97 8:34a John
409  * Added code to read TGA files.
410  * 
411  * 38    6/20/97 1:50p John
412  * added rle code to bmpman.  made gr8_aabitmap use it.
413  * 
414  * 37    6/18/97 12:07p John
415  * fixed some color bugs
416  * 
417  * 36    6/17/97 8:58p Lawrance
418  * fixed bug with not nulling bm.data with USER bitmaps
419  * 
420  * 35    6/12/97 2:44a Lawrance
421  * changed bm_unlock() to take an index into bm_bitmaps().  Added
422  * ref_count to bitmap_entry struct
423  * 
424  * 34    5/20/97 10:36a John
425  * Fixed problem with user bitmaps and direct3d caching.
426  * 
427  * 33    5/14/97 1:59p John
428  * fixed a palette bug with vclips.
429  * 
430  * 32    3/24/97 4:43p John
431  * speed up chunked collision detection by only checking cubes the vector
432  * goes through.
433  * 
434  * 31    3/24/97 3:25p John
435  * Cleaned up and restructured model_collide code and fvi code.  In fvi
436  * made code that finds uvs work..  Added bm_get_pixel to BmpMan.
437  * 
438  * 30    3/11/97 2:49p Allender
439  * 
440  * 29    2/18/97 9:43a Lawrance
441  * added Assert() in bm_release
442  * 
443  * 28    1/22/97 4:29p John
444  * maybe fixed bug with code that counts total bytes of texture ram used.
445  * 
446  * 27    1/22/97 4:19p Lawrance
447  * added flags to bm_create to allow transparency
448  * 
449  * 26    1/21/97 5:24p John
450  * fixed another bug with bm_release.
451  * 
452  * 25    1/21/97 5:12p John
453  * fixed bug with case
454  * 
455  * 24    1/21/97 5:02p John
456  * Added code for 8bpp user bitmaps.
457  * 
458  * 23    1/09/97 11:35a John
459  * Added some 2d functions to get/put screen images.
460  * 
461  * 22    11/26/96 6:50p John
462  * Added some more hicolor primitives.  Made windowed mode run as current
463  * bpp, if bpp is 8,16,or 32.
464  * 
465  * 21    11/26/96 9:44a Allender
466  * Allow for use of different bitmap palettes
467  * 
468  * 20    11/25/96 10:36a Allender
469  * started working on 32 bpp support.  Added 15 bpp.
470  * 
471  * 19    11/18/96 1:51p Allender
472  * fix up manager code to reread bitmaps if needed in newer bit depth
473  * 
474  * 18    11/15/96 4:24p Allender
475  * more bmpman stuff -- only free bitmap slots when releasing copied
476  * texture -- otherwise, only release the data for the bitmap
477  * 
478  * 17    11/15/96 3:33p Allender
479  * added support for converting to 16 bit textures when requested with
480  * bm_load.  Added some other management functions
481  * 
482  * 16    11/13/96 4:51p Allender
483  * started overhaul of bitmap manager.  bm_load no longer actually load
484  * the data, only the info for the bitmap.  Locking the bitmap now forces
485  * load when no data present (or will if bpp changes)
486  *
487  * $NoKeywords: $
488  */
489
490 #include <ctype.h>
491 #include "pstypes.h"
492 #include "pcxutils.h"
493 #include "bmpman.h"
494 #include "palman.h"
495 #include "2d.h"
496 #include "animplay.h"
497 #include "timer.h"
498 #include "systemvars.h"
499 #include "key.h"
500 #include "packunpack.h"
501 #include "cfile.h"
502 #include "grinternal.h"
503 #include "tgautils.h"
504 #include "ship.h"
505
506 #ifndef NDEBUG
507 #define BMPMAN_NDEBUG
508 #endif
509
510 // keep this defined to use per-ship nondarkening pixels
511 #define BMPMAN_SPECIAL_NONDARK
512
513 int bm_inited = 0;
514
515 #define BM_TYPE_NONE            0
516 #define BM_TYPE_PCX                     1
517 #define BM_TYPE_USER            2
518 #define BM_TYPE_ANI                     3               // in-house ANI format
519 #define BM_TYPE_TGA                     4               // 16 bit targa
520
521 typedef union bm_extra_info     {
522         struct {
523                 // Stuff needed for animations
524                 int             first_frame;                                                            // used for animations -- points to index of first frame
525                 ubyte           num_frames;                                                                     // used for animation -- number of frames in the animation
526                 ubyte           fps;                                                                                    // used for animation -- frames per second
527         } ani;
528         struct {
529                 // Stuff needed for user bitmaps
530                 void            *data;                                                                  // For user bitmaps, this is where the data comes from
531                 ubyte           bpp;                                                                    // For user bitmaps, this is what format the data is
532                 ubyte           flags;                                                                  // Flags passed to bm_create
533         } user;
534 } bm_extra_info;
535
536 typedef struct bitmap_entry     {
537         // identification
538         char            filename[MAX_FILENAME_LEN];                     // filename for this bitmap
539
540         uint            signature;                                                                      // a unique signature identifying the data
541         uint            palette_checksum;                                                       // checksum used to be sure bitmap is in current palette
542         int             handle;                                                                         // Handle = id*MAX_BITMAPS + bitmapnum
543         int             last_used;                                                                      // When this bitmap was last used
544
545         ubyte           type;                                                                                   // PCX, USER, ANI, etc
546         signed char     ref_count;                                                              // Number of locks on bitmap.  Can't unload unless ref_count is 0.
547
548         // Stuff to keep track of usage
549         ubyte           preloaded;                                                                      // If set, then this was loaded from the lst file
550         ubyte           used_flags;                                                                     // What flags it was accessed thru
551
552         // Bitmap info
553         bitmap  bm;
554
555         // Data for animations and user bitmaps
556         bm_extra_info   info;           
557
558 #ifdef BMPMAN_NDEBUG
559         // bookeeping
560         ubyte           used_last_frame;                                                        // If set, then it was used last frame
561         ubyte           used_this_frame;                                                        // If set, then it was used this frame
562         int             data_size;                                                                      // How much data this bitmap uses
563         int             used_count;                                                                     // How many times it was accessed
564 #endif
565 } bitmap_entry;
566
567 uint Bm_next_signature = 0x1234;
568
569 bitmap_entry bm_bitmaps[MAX_BITMAPS];
570
571 int bm_texture_ram = 0;
572
573 // Bm_max_ram - How much RAM bmpman can use for textures.
574 // Set to <1 to make it use all it wants.
575 int Bm_max_ram = 0;             //16*1024*1024;                 // Only use 16 MB for textures
576
577 int bm_next_handle = 1;
578
579 int Bm_paging = 0;
580
581 static int Bm_low_mem = 0;                      
582
583 // 16 bit pixel formats
584 int Bm_pixel_format = BM_PIXEL_FORMAT_ARGB;
585
586 // get and put functions for 16 bit pixels - neat bit slinging, huh?
587 #define BM_SET_R_ARGB(p, r)     { p[1] &= ~(0x7c); p[1] |= ((r & 0x1f) << 2); }
588 #define BM_SET_G_ARGB(p, g)     { p[0] &= ~(0xe0); p[1] &= ~(0x03); p[0] |= ((g & 0x07) << 5); p[1] |= ((g & 0x18) >> 3); }
589 #define BM_SET_B_ARGB(p, b)     { p[0] &= ~(0x1f); p[0] |= b & 0x1f; }
590 #define BM_SET_A_ARGB(p, a)     { p[1] &= ~(0x80); p[1] |= ((a & 0x01) << 7); }
591
592 #define BM_SET_R_D3D(p, r)              { *p |= (ushort)(( (int)r / Gr_current_red->scale ) << Gr_current_red->shift); }
593 #define BM_SET_G_D3D(p, g)              { *p |= (ushort)(( (int)g / Gr_current_green->scale ) << Gr_current_green->shift); }
594 #define BM_SET_B_D3D(p, b)              { *p |= (ushort)(( (int)b / Gr_current_blue->scale ) << Gr_current_blue->shift); }
595 #define BM_SET_A_D3D(p, a)              { if(a == 0){ *p = (ushort)Gr_current_green->mask; } }
596
597 #define BM_SET_R(p, r)  { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_R_ARGB(((char*)p), r); break; case BM_PIXEL_FORMAT_D3D: BM_SET_R_D3D(p, r); break; default: Int3(); } }
598 #define BM_SET_G(p, g)  { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_G_ARGB(((char*)p), g); break; case BM_PIXEL_FORMAT_D3D: BM_SET_G_D3D(p, g); break; default: Int3(); } }
599 #define BM_SET_B(p, b)  { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_B_ARGB(((char*)p), b); break; case BM_PIXEL_FORMAT_D3D: BM_SET_B_D3D(p, b); break;  default: Int3(); } }
600 #define BM_SET_A(p, a)  { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_A_ARGB(((char*)p), a); break; case BM_PIXEL_FORMAT_D3D: BM_SET_A_D3D(p, a); break;  default: Int3(); } }
601
602 // ===========================================
603 // Mode: 0 = High memory
604 //       1 = Low memory ( every other frame of ani's)
605 //       2 = Debug low memory ( only use first frame of each ani )
606 void bm_set_low_mem( int mode )
607 {
608         Assert( (mode >= 0)  && (mode<=2 ));
609         Bm_low_mem = mode;
610 }
611
612
613 static int bm_get_next_handle()
614 {
615         int n = bm_next_handle;
616         bm_next_handle++;
617         if ( bm_next_handle > 30000 )   {
618                 bm_next_handle = 1;
619         }
620         return n;
621 }
622
623 // Frees a bitmaps data if it should, and
624 // Returns true if bitmap n can free it's data.
625 static void bm_free_data(int n)
626 {
627         bitmap_entry    *be;
628         bitmap                  *bmp;
629
630         Assert( n >= 0 && n < MAX_BITMAPS );
631
632         be = &bm_bitmaps[n];
633         bmp = &be->bm;
634
635         // If there isn't a bitmap in this structure, don't
636         // do anything but clear out the bitmap info
637         if ( be->type==BM_TYPE_NONE) 
638                 goto SkipFree;
639
640         // If this bitmap doesn't have any data to free, skip
641         // the freeing it part of this.
642         if ( bmp->data == 0 ) 
643                 goto SkipFree;
644
645         // Don't free up memory for user defined bitmaps, since
646         // BmpMan isn't the one in charge of allocating/deallocing them.
647         if ( ( be->type==BM_TYPE_USER ) )       
648                 goto SkipFree;
649
650         // Free up the data now!
651
652         //      mprintf(( "Bitmap %d freed %d bytes\n", n, bm_bitmaps[n].data_size ));
653         #ifdef BMPMAN_NDEBUG
654                 bm_texture_ram -= be->data_size;
655         #endif
656         free((void *)bmp->data);
657
658 SkipFree:
659
660         // Clear out & reset the bitmap data structure
661         bmp->flags = 0;
662         bmp->bpp = 0;
663         bmp->data = 0;
664         bmp->palette = NULL;
665         #ifdef BMPMAN_NDEBUG
666                 be->data_size = 0;
667         #endif
668         be->signature = Bm_next_signature++; 
669 }
670
671
672 #ifdef BMPMAN_NDEBUG
673
674 int Bm_ram_freed = 0;
675
676 static void bm_free_some_ram( int n, int size )
677 {
678 /*
679         if ( Bm_max_ram < 1 ) return;
680         if ( bm_texture_ram + size < Bm_max_ram ) return;
681
682         int current_time = timer_get_milliseconds();
683
684         while( bm_texture_ram + size > Bm_max_ram )     {
685                 Bm_ram_freed++;
686
687                 // Need to free some RAM up!
688                 int i, oldest=-1, best_val=0;
689                 for (i = 0; i < MAX_BITMAPS; i++)       {
690                         if ( (bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].first_frame!=bm_bitmaps[n].first_frame) && (bm_bitmaps[i].ref_count==0) && (bm_bitmaps[i].data_size>0) )    {
691                                 int page_func = ( current_time-bm_bitmaps[i].last_used)*bm_bitmaps[i].data_size;
692                                 if ( (oldest==-1) || (page_func>best_val) )     {
693                                         oldest=i;
694                                         best_val = page_func;
695                                 }
696                         }
697                 }
698
699                 if ( oldest > -1 )      {
700                         //mprintf(( "Freeing bitmap '%s'\n", bm_bitmaps[oldest].filename ));
701                         for (i=0; i<bm_bitmaps[oldest].num_frames; i++ )        {
702                                 bm_free_data(bm_bitmaps[oldest].first_frame+i);
703                         }
704                 } else {
705                         //mprintf(( "Couldn't free enough! %d\n", bm_texture_ram ));
706                         break;
707                 }
708         }       
709 */
710 }
711
712 #endif
713
714 static void *bm_malloc( int n, int size )
715 {
716         Assert( n >= 0 && n < MAX_BITMAPS );
717 //      mprintf(( "Bitmap %d allocated %d bytes\n", n, size ));
718         #ifdef BMPMAN_NDEBUG
719         bm_free_some_ram( n, size );
720         Assert( bm_bitmaps[n].data_size == 0 );
721         bm_bitmaps[n].data_size += size;
722         bm_texture_ram += size;
723         #endif
724         return malloc(size);
725 }
726
727 void bm_close()
728 {
729         int i;
730         if ( bm_inited )        {
731                 for (i=0; i<MAX_BITMAPS; i++ )  {
732                         bm_free_data(i);                        // clears flags, bbp, data, etc
733                 }
734                 bm_inited = 0;
735         }
736 }
737
738
739 void bm_init()
740 {
741         int i;
742
743         mprintf(( "Size of bitmap info = %d KB\n", sizeof( bm_bitmaps )/1024 ));
744         mprintf(( "Size of bitmap extra info = %d bytes\n", sizeof( bm_extra_info ) ));
745         
746         if (!bm_inited) {
747                 bm_inited = 1;
748                 atexit(bm_close);
749         }
750         
751         for (i=0; i<MAX_BITMAPS; i++ ) {
752                 bm_bitmaps[i].filename[0] = '\0';
753                 bm_bitmaps[i].type = BM_TYPE_NONE;
754                 bm_bitmaps[i].info.user.data = NULL;
755                 bm_bitmaps[i].bm.data = 0;
756                 bm_bitmaps[i].bm.palette = NULL;
757                 #ifdef BMPMAN_NDEBUG
758                         bm_bitmaps[i].data_size = 0;
759                         bm_bitmaps[i].used_count = 0;
760                         bm_bitmaps[i].used_last_frame = 0;
761                         bm_bitmaps[i].used_this_frame = 0;
762                 #endif
763                 bm_free_data(i);        // clears flags, bbp, data, etc
764         }
765
766
767 }
768
769 #ifdef BMPMAN_NDEBUG
770
771 // Returns number of bytes of bitmaps locked this frame
772 // ntotal = number of bytes of bitmaps locked this frame
773 // nnew = number of bytes of bitmaps locked this frame that weren't locked last frame
774 void bm_get_frame_usage(int *ntotal, int *nnew)
775 {
776         int i;
777         
778         *ntotal = 0;
779         *nnew = 0;
780
781         for (i=0; i<MAX_BITMAPS; i++ ) {
782                 if ( (bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].used_this_frame))   {
783                         if ( !bm_bitmaps[i].used_last_frame )   {
784                                 *nnew += bm_bitmaps[i].bm.w*bm_bitmaps[i].bm.h; 
785                         }
786                         *ntotal += bm_bitmaps[i].bm.w*bm_bitmaps[i].bm.h;
787                 }
788                 bm_bitmaps[i].used_last_frame = bm_bitmaps[i].used_this_frame;
789                 bm_bitmaps[i].used_this_frame = 0;
790         }
791
792 }
793 #else
794 void bm_get_frame_usage(int *ntotal, int *nnew)
795 {
796 }
797 #endif
798
799 // given a loaded bitmap with valid info, calculate sections
800 void bm_calc_sections(bitmap *be)
801 {
802         int idx;
803
804         // number of x and y sections
805         be->sections.num_x = (ubyte)(be->w / MAX_BMAP_SECTION_SIZE);
806         if((be->sections.num_x * MAX_BMAP_SECTION_SIZE) < be->w){
807                 be->sections.num_x++;
808         }
809         be->sections.num_y = (ubyte)(be->h / MAX_BMAP_SECTION_SIZE);
810         if((be->sections.num_y * MAX_BMAP_SECTION_SIZE) < be->h){
811                 be->sections.num_y++;
812         }
813
814         // calculate the offsets for each section
815         for(idx=0; idx<be->sections.num_x; idx++){
816                 be->sections.sx[idx] = (ushort)(MAX_BMAP_SECTION_SIZE * idx);
817         }
818         for(idx=0; idx<be->sections.num_y; idx++){
819                 be->sections.sy[idx] = (ushort)(MAX_BMAP_SECTION_SIZE * idx);
820         }
821 }
822
823 // Creates a bitmap that exists in RAM somewhere, instead
824 // of coming from a disk file.  You pass in a pointer to a
825 // block of 32 (or 8)-bit-per-pixel data.  Right now, the only
826 // bpp you can pass in is 32 or 8.  On success, it returns the
827 // bitmap number.  You cannot free that RAM until bm_release
828 // is called on that bitmap.
829 int bm_create( int bpp, int w, int h, void * data, int flags )
830 {
831         int i, n, first_slot = MAX_BITMAPS;
832
833         // Assert((bpp==32)||(bpp==8));
834         if(bpp != 16){
835                 Assert(flags & BMP_AABITMAP);
836         } else {
837                 Assert(bpp == 16);
838         }
839
840         if ( !bm_inited ) bm_init();
841
842         for (i = MAX_BITMAPS-1; i >= 0; i-- ) {
843                 if ( bm_bitmaps[i].type == BM_TYPE_NONE )       {
844                         first_slot = i;
845                         break;
846                 }
847         }
848
849         n = first_slot;
850         Assert( n > -1 );
851
852         // Out of bitmap slots
853         if ( n == -1 ) return -1;
854
855         memset( &bm_bitmaps[n], 0, sizeof(bitmap_entry) );
856
857         sprintf( bm_bitmaps[n].filename, "TMP%dx%d", w, h );
858         bm_bitmaps[n].type = BM_TYPE_USER;
859         bm_bitmaps[n].palette_checksum = 0;
860
861         bm_bitmaps[n].bm.w = short(w);
862         bm_bitmaps[n].bm.h = short(h);
863         bm_bitmaps[n].bm.rowsize = short(w);
864         bm_bitmaps[n].bm.bpp = (unsigned char)(bpp);
865         bm_bitmaps[n].bm.flags = 0;
866         bm_bitmaps[n].bm.flags |= flags;
867         bm_bitmaps[n].bm.data = 0;
868         bm_bitmaps[n].bm.palette = NULL;
869
870         bm_bitmaps[n].info.user.bpp = ubyte(bpp);
871         bm_bitmaps[n].info.user.data = data;
872         bm_bitmaps[n].info.user.flags = ubyte(flags);
873
874         bm_bitmaps[n].signature = Bm_next_signature++;
875
876         bm_bitmaps[n].handle = bm_get_next_handle()*MAX_BITMAPS + n;
877         bm_bitmaps[n].last_used = -1;
878
879         // fill in section info
880         bm_calc_sections(&bm_bitmaps[n].bm);
881         
882         return bm_bitmaps[n].handle;
883 }
884
885 // sub helper function. Given a raw filename and an extension, try and find the bitmap
886 // returns -1 if it could not be found
887 //          0 if it was found as a file
888 //          1 if it already exists, fills in handle
889 int Bm_ignore_duplicates = 0;
890 int bm_load_sub(char *real_filename, char *ext, int *handle)
891 {       
892         int i;
893         char filename[MAX_FILENAME_LEN] = "";
894         
895         strcpy( filename, real_filename );
896         strcat( filename, ext );        
897         for (i=0; i<(int)strlen(filename); i++ ){
898                 filename[i] = char(tolower(filename[i]));
899         }               
900
901         // try to find given filename to see if it has been loaded before
902         if(!Bm_ignore_duplicates){
903                 for (i = 0; i < MAX_BITMAPS; i++) {
904                         if ( (bm_bitmaps[i].type != BM_TYPE_NONE) && !stricmp(filename, bm_bitmaps[i].filename) ) {
905                                 nprintf (("BmpMan", "Found bitmap %s -- number %d\n", filename, i));
906                                 *handle = bm_bitmaps[i].handle;
907                                 return 1;
908                         }
909                 }       
910         }
911
912         // try and find the file
913         /*
914         CFILE *test = cfopen(filename, "rb");
915         if(test != NULL){
916                 cfclose(test);
917                 return 0;
918         }
919         */
920
921         // could not be found
922         return 0;
923 }
924
925 // This loads a bitmap so we can draw with it later.
926 // It returns a negative number if it couldn't load
927 // the bitmap.   On success, it returns the bitmap
928 // number.  Function doesn't acutally load the data, only
929 // width, height, and possibly flags.
930 int bm_load( char * real_filename )
931 {
932         int i, n, first_slot = MAX_BITMAPS;
933         int w, h, bpp;
934         char filename[MAX_FILENAME_LEN];
935         int tga = 0;
936         int handle;
937         int found = 0;
938
939         if ( !bm_inited ) bm_init();
940
941         // nice little trick for keeping standalone memory usage way low - always return a bogus bitmap 
942         if(Game_mode & GM_STANDALONE_SERVER){
943                 strcpy(filename,"test128");
944         }
945
946         // make sure no one passed an extension
947         strcpy( filename, real_filename );
948         char *p = strchr( filename, '.' );
949         if ( p ) {
950                 mprintf(( "Someone passed an extension to bm_load for file '%s'\n", real_filename ));
951                 //Int3();
952                 *p = 0;
953         }
954          
955         // try and find the pcx file            
956         switch(bm_load_sub(filename, ".pcx", &handle)){
957         // error
958         case -1:
959                 break;
960
961         // found as a file
962         case 0:
963                 found = 1;
964                 strcat(filename, ".pcx");
965                 break;
966
967         // found as pre-existing
968         case 1:
969                 found = 1;
970                 return handle;          
971         }
972
973         if(!found){
974                 // try and find the tga file
975                 switch(bm_load_sub(filename, ".tga", &handle)){
976                 // error
977                 case -1:                        
978                         return -1;
979                         break;
980
981                 // found as a file
982                 case 0:                 
983                         strcat(filename, ".tga");
984                         tga = 1;
985                         break;
986
987                 // found as pre-existing
988                 case 1:                                         
989                         return handle;                                  
990                 }
991         }
992
993         // if its a tga file
994         if(tga){
995                 int tga_error=targa_read_header( filename, &w, &h, &bpp, NULL );
996                 if ( tga_error != TARGA_ERROR_NONE )    {
997                         mprintf(( "Couldn't open '%s'\n", filename ));
998                         return -1;
999                 }
1000         }
1001         // if its a pcx file
1002         else {
1003                 int pcx_error=pcx_read_header( filename, &w, &h, NULL );                
1004                 if ( pcx_error != PCX_ERROR_NONE )      {
1005                         mprintf(( "Couldn't open '%s'\n", filename ));
1006                         return -1;
1007                 }
1008         }
1009
1010         // Error( LOCATION, "Unknown bitmap type %s\n", filename );
1011                 
1012         // Find an open slot
1013         for (i = 0; i < MAX_BITMAPS; i++) {
1014                 if ( (bm_bitmaps[i].type == BM_TYPE_NONE) && (first_slot == MAX_BITMAPS) ){
1015                         first_slot = i;
1016                 }
1017         }
1018
1019         n = first_slot;
1020         Assert( n < MAX_BITMAPS );      
1021
1022         if ( n == MAX_BITMAPS ) return -1;      
1023
1024         // ensure fields are cleared out from previous bitmap
1025 //      Assert(bm_bitmaps[n].bm.data == 0);
1026 //      Assert(bm_bitmaps[n].bm.palette == NULL);
1027 //      Assert(bm_bitmaps[n].ref_count == 0 );
1028 //      Assert(bm_bitmaps[n].user_data == NULL);
1029         memset( &bm_bitmaps[n], 0, sizeof(bitmap_entry) );
1030         
1031         // Mark the slot as filled, because cf_read might load a new bitmap
1032         // into this slot.
1033         bm_bitmaps[n].type = tga ? (ubyte)BM_TYPE_TGA : (ubyte)BM_TYPE_PCX;
1034         bm_bitmaps[n].signature = Bm_next_signature++;
1035         Assert ( strlen(filename) < MAX_FILENAME_LEN );
1036         strncpy(bm_bitmaps[n].filename, filename, MAX_FILENAME_LEN-1 );
1037         bm_bitmaps[n].bm.w = short(w);
1038         bm_bitmaps[n].bm.rowsize = short(w);
1039         bm_bitmaps[n].bm.h = short(h);
1040         bm_bitmaps[n].bm.bpp = 0;
1041         bm_bitmaps[n].bm.flags = 0;
1042         bm_bitmaps[n].bm.data = 0;
1043         bm_bitmaps[n].bm.palette = NULL;
1044
1045         bm_bitmaps[n].palette_checksum = 0;
1046         bm_bitmaps[n].handle = bm_get_next_handle()*MAX_BITMAPS + n;
1047         bm_bitmaps[n].last_used = -1;
1048
1049         // fill in section info
1050         bm_calc_sections(&bm_bitmaps[n].bm);
1051
1052         return bm_bitmaps[n].handle;
1053 }
1054
1055 // special load function. basically allows you to load a bitmap which already exists (by filename). 
1056 // this is useful because in some cases we need to have a bitmap which is locked in screen format
1057 // _and_ texture format, such as pilot pics and squad logos
1058 int bm_load_duplicate(char *filename)
1059 {
1060         int ret;
1061
1062         // ignore duplicates
1063         Bm_ignore_duplicates = 1;
1064         
1065         // load
1066         ret = bm_load(filename);
1067
1068         // back to normal
1069         Bm_ignore_duplicates = 0;
1070
1071         return ret;
1072 }
1073
1074 DCF(bm_frag,"Shows BmpMan fragmentation")
1075 {
1076         if ( Dc_command )       {
1077
1078                 gr_clear();
1079
1080                 int x=0, y=0;
1081                 int xs=2, ys=2;
1082                 int w=4, h=4;
1083
1084                 for (int i=0; i<MAX_BITMAPS; i++ )      {
1085                         switch( bm_bitmaps[i].type )    {
1086                         case BM_TYPE_NONE:
1087                                 gr_set_color(128,128,128);
1088                                 break;
1089                         case BM_TYPE_PCX:
1090                                 gr_set_color(255,0,0);
1091                                 break;
1092                         case BM_TYPE_USER:
1093                                 gr_set_color(0,255,0);
1094                                 break;
1095                         case BM_TYPE_ANI:
1096                                 gr_set_color(0,0,255);
1097                                 break;
1098                         }
1099
1100                         gr_rect( x+xs, y+ys, w, h );
1101                         x += w+xs+xs;
1102                         if ( x > 639 )  {
1103                                 x = 0;
1104                                 y += h + ys + ys;
1105                         }
1106
1107                 }
1108
1109                 gr_flip();
1110                 key_getch();
1111         }
1112 }
1113
1114 static int find_block_of(int n)
1115 {
1116         int i, cnt, nstart;
1117
1118         cnt=0;
1119         nstart = 0;
1120         for (i=0; i<MAX_BITMAPS; i++ )  {
1121                 if ( bm_bitmaps[i].type == BM_TYPE_NONE )       {
1122                         if (cnt==0) nstart = i;
1123                         cnt++;
1124                 } else
1125                         cnt=0;
1126                 if ( cnt == n ) return nstart;
1127         }
1128
1129         // Error( LOCATION, "Couldn't find block of %d frames\n", n );
1130         return -1;
1131 }
1132
1133 // ------------------------------------------------------------------
1134 // bm_load_animation()
1135 //
1136 //      input:          filename                =>              filename of animation
1137 //                                      nframes         =>              OUTPUT parameter:       number of frames in the animation
1138 //                                      fps                     =>              OUTPUT/OPTIONAL parameter: intended fps for the animation
1139 //
1140 // returns:             bitmap number of first frame in the animation
1141 //
1142 int bm_load_animation( char *real_filename, int *nframes, int *fps, int can_drop_frames)
1143 {
1144         int     i, n;
1145         anim    the_anim;
1146         CFILE   *fp;
1147         char filename[MAX_FILENAME_LEN];
1148
1149         if ( !bm_inited ) bm_init();
1150
1151         strcpy( filename, real_filename );
1152         char *p = strchr( filename, '.' );
1153         if ( p ) {
1154                 mprintf(( "Someone passed an extension to bm_load_animation for file '%s'\n", real_filename ));
1155                 //Int3();
1156                 *p = 0;
1157         }
1158         strcat( filename, ".ani" );
1159
1160         if ( (fp = cfopen(filename, "rb")) == NULL ) {
1161 //              Error(LOCATION,"Could not open filename %s in bm_load_ani()\n", filename);
1162                 return -1;
1163         }
1164
1165         int reduced = 0;
1166 #ifndef NDEBUG
1167         // for debug of ANI sizes
1168         strcpy(the_anim.name, real_filename);
1169 #endif
1170         anim_read_header(&the_anim, fp);
1171         if ( can_drop_frames )  {
1172                 if ( Bm_low_mem == 1 )  {
1173                         reduced = 1;
1174                         the_anim.total_frames = ( the_anim.total_frames+1)/2;
1175                 } else if ( Bm_low_mem == 2 )   {
1176                         the_anim.total_frames = 1;      
1177                 }
1178         }
1179         cfclose(fp);
1180
1181         *nframes = the_anim.total_frames;
1182         if ( fps != NULL )      {
1183                 if ( reduced )  {
1184                         *fps = the_anim.fps / 2;
1185                 } else {
1186                         *fps = the_anim.fps;
1187                 }
1188         }
1189
1190         // first check to see if this ani already has it's frames loaded
1191         for (i = 0; i < MAX_BITMAPS; i++) {
1192                 if ( (bm_bitmaps[i].type == BM_TYPE_ANI) && !stricmp(filename, bm_bitmaps[i].filename) ) {
1193                         break;
1194                 }
1195         }
1196         
1197         if ( i < MAX_BITMAPS ) {
1198                 // in low memory modes this can happen
1199                 if(!Bm_low_mem){
1200                         Assert(bm_bitmaps[i].info.ani.num_frames == *nframes);
1201                 }
1202                 return bm_bitmaps[i].handle;
1203         }
1204
1205         n = find_block_of(*nframes);
1206         if(n < 0){
1207                 return -1;
1208         }
1209         // Assert( n >= 0 );
1210
1211         int first_handle = bm_get_next_handle();
1212
1213         Assert ( strlen(filename) < MAX_FILENAME_LEN );
1214         for ( i = 0; i < *nframes; i++ ) {
1215                 memset( &bm_bitmaps[n+i], 0, sizeof(bitmap_entry) );
1216                 bm_bitmaps[n+i].info.ani.first_frame = n;
1217                 bm_bitmaps[n+i].info.ani.num_frames = ubyte(the_anim.total_frames);
1218                 bm_bitmaps[n+i].info.ani.fps = ubyte(the_anim.fps);
1219                 bm_bitmaps[n+i].bm.w = short(the_anim.width);
1220                 bm_bitmaps[n+i].bm.rowsize = short(the_anim.width);
1221                 bm_bitmaps[n+i].bm.h = short(the_anim.height);
1222                 if ( reduced )  {
1223                         bm_bitmaps[n+i].bm.w /= 2;
1224                         bm_bitmaps[n+i].bm.rowsize /= 2;
1225                         bm_bitmaps[n+i].bm.h /= 2;
1226                 }
1227                 bm_bitmaps[n+i].bm.flags = 0;
1228                 bm_bitmaps[n+i].bm.bpp = 0;
1229                 bm_bitmaps[n+i].bm.data = 0;
1230                 bm_bitmaps[n+i].bm.palette = NULL;
1231                 bm_bitmaps[n+i].type = BM_TYPE_ANI;
1232                 bm_bitmaps[n+i].palette_checksum = 0;
1233                 bm_bitmaps[n+i].signature = Bm_next_signature++;
1234                 bm_bitmaps[n+i].handle = first_handle*MAX_BITMAPS + n+i;
1235                 bm_bitmaps[n+i].last_used = -1;
1236
1237                 // fill in section info
1238                 bm_calc_sections(&bm_bitmaps[n+i].bm);
1239
1240                 if ( i == 0 )   {
1241                         sprintf( bm_bitmaps[n+i].filename, "%s", filename );
1242                 } else {
1243                         sprintf( bm_bitmaps[n+i].filename, "%s[%d]", filename, i );
1244                 }
1245         }
1246
1247         return bm_bitmaps[n].handle;
1248 }
1249
1250 // Gets info.   w,h,or flags,nframes or fps can be NULL if you don't care.
1251 void bm_get_info( int handle, int *w, int * h, ubyte * flags, int *nframes, int *fps, bitmap_section_info **sections )
1252 {
1253         bitmap * bmp;
1254
1255         if ( !bm_inited ) return;
1256
1257         int bitmapnum = handle % MAX_BITMAPS;
1258         Assert( bm_bitmaps[bitmapnum].handle == handle );               // INVALID BITMAP HANDLE!       
1259         
1260         if ( (bm_bitmaps[bitmapnum].type == BM_TYPE_NONE) || (bm_bitmaps[bitmapnum].handle != handle) ) {
1261                 if (w) *w = 0;
1262                 if (h) *h = 0;
1263                 if (flags) *flags = 0;
1264                 if (nframes) *nframes=0;
1265                 if (fps) *fps=0;
1266                 if (sections != NULL) *sections = NULL;
1267                 return;
1268         }
1269
1270         bmp = &(bm_bitmaps[bitmapnum].bm);
1271
1272         if (w) *w = bmp->w;
1273         if (h) *h = bmp->h;
1274         if (flags) *flags = bmp->flags;
1275         if ( bm_bitmaps[bitmapnum].type == BM_TYPE_ANI )        {
1276                 if (nframes) {
1277                         *nframes = bm_bitmaps[bitmapnum].info.ani.num_frames;
1278                 } 
1279                 if (fps) {
1280                         *fps= bm_bitmaps[bitmapnum].info.ani.fps;
1281                 }
1282         } else {
1283                 if (nframes) {
1284                         *nframes = 1;
1285                 } 
1286                 if (fps) {
1287                         *fps= 0;
1288                 }
1289         }
1290         if(sections != NULL){
1291                 *sections = &bm_bitmaps[bitmapnum].bm.sections;
1292         }
1293 }
1294
1295 uint bm_get_signature( int handle )
1296 {
1297         if ( !bm_inited ) bm_init();
1298
1299         int bitmapnum = handle % MAX_BITMAPS;
1300         Assert( bm_bitmaps[bitmapnum].handle == handle );               // INVALID BITMAP HANDLE
1301
1302         return bm_bitmaps[bitmapnum].signature;
1303 }
1304
1305 extern int palman_is_nondarkening(int r,int g, int b);
1306 static void bm_convert_format( int bitmapnum, bitmap *bmp, ubyte bpp, ubyte flags )
1307 {       
1308         int idx;        
1309         int r, g, b, a;
1310
1311         if(Fred_running || Pofview_running || Is_standalone){
1312                 Assert(bmp->bpp == 8);
1313
1314                 return;
1315         } else {
1316                 if(flags & BMP_AABITMAP){
1317                         Assert(bmp->bpp == 8);
1318                 } else {
1319                         Assert(bmp->bpp == 16);
1320                 }
1321         }
1322
1323         // maybe swizzle to be an xparent texture
1324         if(!(bmp->flags & BMP_TEX_XPARENT) && (flags & BMP_TEX_XPARENT)){
1325                 for(idx=0; idx<bmp->w*bmp->h; idx++){                   
1326                         
1327                         // if the pixel is transparent
1328                         if ( ((ushort*)bmp->data)[idx] == Gr_t_green.mask)      {
1329                                 switch(Bm_pixel_format){
1330                                 // 1555, all we need to do is zero the whole thing
1331                                 case BM_PIXEL_FORMAT_ARGB:
1332                                 case BM_PIXEL_FORMAT_ARGB_D3D:
1333                                         ((ushort*)bmp->data)[idx] = 0;
1334                                         break;
1335                                 // d3d format
1336                                 case BM_PIXEL_FORMAT_D3D:                                                                       
1337                                         r = g = b = a = 0;
1338                                         r /= Gr_t_red.scale;
1339                                         g /= Gr_t_green.scale;
1340                                         b /= Gr_t_blue.scale;
1341                                         a /= Gr_t_alpha.scale;
1342                                         ((ushort*)bmp->data)[idx] = (unsigned short)((a<<Gr_t_alpha.shift) | (r << Gr_t_red.shift) | (g << Gr_t_green.shift) |  (b << Gr_t_blue.shift));
1343                                         break;
1344                                 default:
1345                                         Int3();
1346                                 }
1347                         }
1348                 }
1349
1350                 bmp->flags |= BMP_TEX_XPARENT;
1351         }       
1352 }
1353
1354 // basically, map the bitmap into the current palette. used to be done for all pcx's, now just for
1355 // Fred, since its the only thing that uses the software tmapper
1356 void bm_swizzle_8bit_for_fred(bitmap_entry *be, bitmap *bmp, ubyte *data, ubyte *palette)
1357 {               
1358         int pcx_xparent_index = -1;
1359         int i;
1360         int r, g, b;
1361         ubyte palxlat[256];
1362
1363         for (i=0; i<256; i++ ) {
1364                 r = palette[i*3];
1365                 g = palette[i*3+1];
1366                 b = palette[i*3+2];
1367                 if ( g == 255 && r == 0 && b == 0 ) {
1368                         palxlat[i] = 255;
1369                         pcx_xparent_index = i;
1370                 } else {                        
1371                         palxlat[i] = (ubyte)(palette_find( r, g, b ));                  
1372                 }
1373         }               
1374         for (i=0; i<bmp->w * bmp->h; i++ ) {            
1375                 ubyte c = palxlat[data[i]];                     
1376                 data[i] = c;            
1377         }                       
1378         be->palette_checksum = gr_palette_checksum;     
1379 }
1380
1381 void bm_lock_pcx( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1382 {       
1383         ubyte *data, *palette;
1384         ubyte pal[768];
1385         palette = NULL;
1386
1387         // Unload any existing data
1388         bm_free_data( bitmapnum );      
1389
1390         // allocate bitmap data
1391         if(bpp == 8){
1392                 // Assert(Fred_running || Pofview_running || Is_standalone);            
1393                         data = (ubyte *)bm_malloc(bitmapnum, bmp->w * bmp->h );
1394                 #ifdef BMPMAN_NDEBUG
1395                         Assert( be->data_size == bmp->w * bmp->h );
1396                 #endif
1397                 palette = pal;
1398                 bmp->data = (uint)data;
1399                 bmp->bpp = 8;
1400                 bmp->palette = gr_palette;
1401                 memset( data, 0, bmp->w * bmp->h);
1402         } else {
1403                 data = (ubyte*)bm_malloc(bitmapnum, bmp->w * bmp->h * 2);       
1404                 bmp->bpp = 16;
1405                 bmp->data = (uint)data;
1406                 bmp->palette = NULL;
1407                 memset( data, 0, bmp->w * bmp->h * 2);
1408         }       
1409
1410         Assert( &be->bm == bmp );
1411         #ifdef BMPMAN_NDEBUG
1412                 Assert( be->data_size > 0 );
1413         #endif
1414
1415         // some sanity checks on flags
1416         Assert(!((flags & BMP_AABITMAP) && (flags & BMP_TEX_ANY)));                                             // no aabitmap textures
1417         Assert(!((flags & BMP_TEX_XPARENT) && (flags & BMP_TEX_NONDARK)));                      // can't be a transparent texture and a nondarkening texture 
1418         Assert(!((flags & BMP_TEX_NONDARK) && (gr_screen.mode == GR_DIRECT3D)));        // D3D should never be trying to get nondarkening textures
1419
1420         if(bpp == 8){
1421                 int pcx_error=pcx_read_bitmap_8bpp( be->filename, data, palette );
1422                 if ( pcx_error != PCX_ERROR_NONE )      {
1423                         // Error( LOCATION, "Couldn't open '%s'\n", be->filename );
1424                         //Error( LOCATION, "Couldn't open '%s'\n", filename );
1425                         //return -1;
1426                 }
1427
1428                 // now swizzle the thing into the proper format
1429                 if(Fred_running || Pofview_running){
1430                         bm_swizzle_8bit_for_fred(be, bmp, data, palette);
1431                 }
1432         } else {        
1433                 int pcx_error;
1434
1435                 // load types
1436                 if(flags & BMP_AABITMAP){
1437                         pcx_error = pcx_read_bitmap_16bpp_aabitmap( be->filename, data );
1438                 } else if(flags & BMP_TEX_NONDARK){
1439                         pcx_error = pcx_read_bitmap_16bpp_nondark( be->filename, data );
1440                 } else {
1441                         pcx_error = pcx_read_bitmap_16bpp( be->filename, data );
1442                 }
1443                 if ( pcx_error != PCX_ERROR_NONE )      {
1444                         // Error( LOCATION, "Couldn't open '%s'\n", be->filename );
1445                         //Error( LOCATION, "Couldn't open '%s'\n", filename );
1446                         //return -1;
1447                 }
1448         }
1449
1450         #ifdef BMPMAN_NDEBUG
1451         Assert( be->data_size > 0 );
1452         #endif          
1453         
1454         bmp->flags = 0; 
1455         bm_convert_format( bitmapnum, bmp, bpp, flags );
1456 }
1457
1458 void bm_lock_ani( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1459 {       
1460         anim                            *the_anim;
1461         anim_instance   *the_anim_instance;
1462         bitmap                  *bm;
1463         ubyte                           *frame_data;
1464         int                             size, i;
1465         int                             first_frame, nframes;   
1466
1467         first_frame = be->info.ani.first_frame;
1468         nframes = bm_bitmaps[first_frame].info.ani.num_frames;
1469
1470         if ( (the_anim = anim_load(bm_bitmaps[first_frame].filename)) == NULL ) {
1471                 // Error(LOCATION, "Error opening %s in bm_lock\n", be->filename);
1472         }
1473
1474         if ( (the_anim_instance = init_anim_instance(the_anim, bpp)) == NULL ) {
1475                 // Error(LOCATION, "Error opening %s in bm_lock\n", be->filename);
1476                 anim_free(the_anim);
1477         }
1478
1479         int can_drop_frames = 0;
1480
1481         if ( the_anim->total_frames != bm_bitmaps[first_frame].info.ani.num_frames )    {
1482                 can_drop_frames = 1;
1483         }
1484         bm = &bm_bitmaps[first_frame].bm;
1485         if(bpp == 16){
1486                 size = bm->w * bm->h * 2;
1487         } else {
1488                 size = bm->w * bm->h;
1489         }
1490                 
1491         for ( i=0; i<nframes; i++ )     {
1492                 be = &bm_bitmaps[first_frame+i];
1493                 bm = &bm_bitmaps[first_frame+i].bm;
1494
1495                 // Unload any existing data
1496                 bm_free_data( first_frame+i );
1497
1498                 bm->flags = 0;
1499                 // briefing editor in Fred2 uses aabitmaps (ani's) - force to 8 bit
1500                 if(Fred_running || Is_standalone){
1501                         bm->bpp = 8;
1502                 } else {
1503                         bm->bpp = bpp;
1504                 }
1505                 bm->data = (uint)bm_malloc(first_frame + i, size);
1506
1507                 frame_data = anim_get_next_raw_buffer(the_anim_instance, 0 ,flags & BMP_AABITMAP ? 1 : 0, bm->bpp);
1508
1509                 if ( frame_data == NULL ) {
1510                         // Error(LOCATION,"Fatal error locking .ani file: %s\n", be->filename);
1511                 }               
1512                 
1513                 ubyte *dptr, *sptr;
1514
1515                 sptr = frame_data;
1516                 dptr = (ubyte *)bm->data;
1517
1518                 if ( (bm->w!=the_anim->width) || (bm->h!=the_anim->height) )    {
1519                         // Scale it down
1520                         // Int3();                      // not ready yet - should only be ingame
1521         
1522                         // 8 bit
1523                         if(bpp == 8){
1524                                 int w,h;
1525                                 fix u, utmp, v, du, dv;
1526
1527                                 u = v = 0;
1528
1529                                 du = ( the_anim->width*F1_0 ) / bm->w;
1530                                 dv = ( the_anim->height*F1_0 ) / bm->h;
1531                                                                                                 
1532                                 for (h = 0; h < bm->h; h++) {
1533                                         ubyte *drow = &dptr[bm->w * h];
1534                                         ubyte *srow = &sptr[f2i(v)*the_anim->width];
1535
1536                                         utmp = u;
1537
1538                                         for (w = 0; w < bm->w; w++) {
1539                                                 *drow++ = srow[f2i(utmp)];
1540                                                 utmp += du;
1541                                         }
1542                                         v += dv;
1543                                 }                       
1544                         }
1545                         // 16 bpp
1546                         else {
1547                                 int w,h;
1548                                 fix u, utmp, v, du, dv;
1549
1550                                 u = v = 0;
1551
1552                                 du = ( the_anim->width*F1_0 ) / bm->w;
1553                                 dv = ( the_anim->height*F1_0 ) / bm->h;
1554                                                                                                 
1555                                 for (h = 0; h < bm->h; h++) {
1556                                         ushort *drow = &((ushort*)dptr)[bm->w * h];
1557                                         ushort *srow = &((ushort*)sptr)[f2i(v)*the_anim->width];
1558
1559                                         utmp = u;
1560
1561                                         for (w = 0; w < bm->w; w++) {
1562                                                 *drow++ = srow[f2i(utmp)];
1563                                                 utmp += du;
1564                                         }
1565                                         v += dv;
1566                                 }                       
1567                         }                       
1568                 } else {
1569                         // 1-to-1 mapping
1570                         memcpy(dptr, sptr, size);
1571                 }               
1572
1573                 bm_convert_format( first_frame+i, bm, bpp, flags );
1574
1575                 // Skip a frame
1576                 if ( (i < nframes-1)  && can_drop_frames )      {
1577                         frame_data = anim_get_next_raw_buffer(the_anim_instance, 0, flags & BMP_AABITMAP ? 1 : 0, bm->bpp);
1578                 }
1579
1580                 //mprintf(( "Checksum = %d\n", be->palette_checksum ));
1581         }
1582
1583         free_anim_instance(the_anim_instance);
1584         anim_free(the_anim);
1585 }
1586
1587
1588 void bm_lock_user( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1589 {
1590         // int idx;     
1591         // ushort bit_16;
1592
1593         // Unload any existing data
1594         bm_free_data( bitmapnum );      
1595
1596         switch( be->info.user.bpp )     {
1597         case 16:                        // user 16 bit bitmap
1598                 bmp->bpp = bpp;
1599                 bmp->flags = be->info.user.flags;               
1600                 bmp->data = (uint)be->info.user.data;                                                           
1601                 break;  
1602         
1603         case 8:                 // Going from 8 bpp to something (probably only for aabitmaps)
1604                 /*
1605                 Assert(flags & BMP_AABITMAP);
1606                 bmp->bpp = 16;
1607                 bmp->data = (uint)malloc(bmp->w * bmp->h * 2);
1608                 bmp->flags = be->info.user.flags;
1609                 bmp->palette = NULL;
1610
1611                 // go through and map the pixels
1612                 for(idx=0; idx<bmp->w * bmp->h; idx++){                 
1613                         bit_16 = (ushort)((ubyte*)be->info.user.data)[idx];                     
1614                         Assert(bit_16 <= 255);
1615
1616                         // stuff the final result
1617                         memcpy((char*)bmp->data + (idx * 2), &bit_16, sizeof(ushort));
1618                 }
1619                 */              
1620                 Assert(flags & BMP_AABITMAP);
1621                 bmp->bpp = bpp;
1622                 bmp->flags = be->info.user.flags;               
1623                 bmp->data = (uint)be->info.user.data;                                                           
1624                 break;
1625                 
1626         // default:
1627                 // Error( LOCATION, "Unhandled user bitmap conversion from %d to %d bpp", be->info.user.bpp, bmp->bpp );
1628         }
1629
1630         bm_convert_format( bitmapnum, bmp, bpp, flags );
1631 }
1632
1633 void bm_lock_tga( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1634 {
1635         ubyte *data;    
1636
1637         // Unload any existing data
1638         bm_free_data( bitmapnum );      
1639
1640         if(Fred_running || Is_standalone){
1641                 Assert(bpp == 8);
1642         } else {
1643                 Assert(bpp == 16);
1644         }
1645
1646         // should never try to make an aabitmap out of a targa
1647         Assert(!(flags & BMP_AABITMAP));
1648
1649         // allocate bitmap data 
1650         if(bpp == 16){
1651                 data = (ubyte*)bm_malloc(bitmapnum, bmp->w * bmp->h * 2);       
1652         } else {
1653                 data = (ubyte*)bm_malloc(bitmapnum, bmp->w * bmp->h);   
1654         }
1655         bmp->bpp = bpp;
1656         bmp->data = (uint)data;
1657         bmp->palette = NULL;
1658         if(bpp == 16){
1659                 memset( data, 0, bmp->w * bmp->h * 2);  
1660         } else {
1661                 memset( data, 0, bmp->w * bmp->h );     
1662         }
1663
1664         Assert( &be->bm == bmp );
1665         #ifdef BMPMAN_NDEBUG
1666         Assert( be->data_size > 0 );
1667         #endif
1668         
1669         int tga_error=targa_read_bitmap( be->filename, data, NULL, (bpp == 16) ? 2 : 1);
1670         if ( tga_error != TARGA_ERROR_NONE )    {
1671                 // Error( LOCATION, "Couldn't open '%s'\n", be->filename );
1672                 //Error( LOCATION, "Couldn't open '%s'\n", filename );
1673                 //return -1;
1674         }
1675
1676         #ifdef BMPMAN_NDEBUG
1677         Assert( be->data_size > 0 );
1678         #endif          
1679         
1680         bmp->flags = 0; 
1681         bm_convert_format( bitmapnum, bmp, bpp, flags );
1682 }
1683
1684 MONITOR( NumBitmapPage );
1685 MONITOR( SizeBitmapPage );
1686
1687 // This locks down a bitmap and returns a pointer to a bitmap
1688 // that can be accessed until you call bm_unlock.   Only lock
1689 // a bitmap when you need it!  This will convert it into the 
1690 // appropriate format also.
1691 bitmap * bm_lock( int handle, ubyte bpp, ubyte flags )
1692 {
1693         bitmap                  *bmp;
1694         bitmap_entry    *be;
1695
1696
1697         if ( !bm_inited ) bm_init();
1698
1699         int bitmapnum = handle % MAX_BITMAPS;
1700         Assert( bm_bitmaps[bitmapnum].handle == handle );               // INVALID BITMAP HANDLE
1701
1702 //      flags &= (~BMP_RLE);
1703
1704         // if we're on a standalone server, aways for it to lock to 8 bits
1705         if(Is_standalone){
1706                 bpp = 8;
1707                 flags = 0;
1708         } 
1709         // otherwise do it as normal
1710         else {
1711                 if(Fred_running || Pofview_running){
1712                         Assert( bpp == 8 );
1713                         Assert( (bm_bitmaps[bitmapnum].type == BM_TYPE_PCX) || (bm_bitmaps[bitmapnum].type == BM_TYPE_ANI) || (bm_bitmaps[bitmapnum].type == BM_TYPE_TGA));
1714                 } else {
1715                         if(flags & BMP_AABITMAP){
1716                                 Assert( bpp == 8 );
1717                         } else {
1718                                 Assert( bpp == 16 );
1719                         }
1720                 }
1721         }
1722
1723         be = &bm_bitmaps[bitmapnum];
1724         bmp = &be->bm;
1725
1726         // If you hit this assert, chances are that someone freed the
1727         // wrong bitmap and now someone is trying to use that bitmap.
1728         // See John.
1729         Assert( be->type != BM_TYPE_NONE );             
1730
1731         // Increment ref count for bitmap since lock was made on it.
1732         Assert(be->ref_count >= 0);
1733         be->ref_count++;                                        // Lock it before we page in data; this prevents a callback from freeing this
1734                                                                                         // as it gets read in
1735
1736         // Mark this bitmap as used this frame
1737         #ifdef BMPMAN_NDEBUG
1738         if ( be->used_this_frame < 255 )        {
1739                 be->used_this_frame++;
1740         }
1741         #endif
1742
1743         // if bitmap hasn't been loaded yet, then load it from disk
1744         // reread the bitmap from disk under certain conditions
1745         int pal_changed = 0;
1746         int rle_changed = 0;
1747         int fake_xparent_changed = 0;   
1748         if ( (bmp->data == 0) || (bpp != bmp->bpp) || pal_changed || rle_changed || fake_xparent_changed ) {
1749                 Assert(be->ref_count == 1);
1750
1751                 if ( be->type != BM_TYPE_USER ) {
1752                         if ( bmp->data == 0 ) {
1753                                 nprintf (("BmpMan","Loading %s for the first time.\n", be->filename));
1754                         } else if ( bpp != bmp->bpp ) {
1755                                 nprintf (("BmpMan","Reloading %s from bitdepth %d to bitdepth %d\n", be->filename, bmp->bpp, bpp));
1756                         } else if ( pal_changed ) {
1757                                 nprintf (("BmpMan","Reloading %s to remap palette\n", be->filename));
1758                         } else if ( rle_changed )       {
1759                                 nprintf (("BmpMan","Reloading %s to change RLE.\n", be->filename));
1760                         } else if ( fake_xparent_changed )      {
1761                                 nprintf (("BmpMan","Reloading %s to change fake xparency.\n", be->filename));
1762                         }
1763                 }
1764
1765                 MONITOR_INC( NumBitmapPage, 1 );
1766                 MONITOR_INC( SizeBitmapPage, bmp->w*bmp->h );
1767
1768                 if ( !Bm_paging )       {
1769                         if ( be->type != BM_TYPE_USER ) {
1770                                 char flag_text[64];
1771                                 strcpy( flag_text, "--" );                                                      
1772                                 nprintf(( "Paging", "Loading %s (%dx%dx%dx%s)\n", be->filename, bmp->w, bmp->h, bpp, flag_text ));
1773                         }
1774                 }
1775
1776                 // select proper format
1777                 if(flags & BMP_AABITMAP){
1778                         BM_SELECT_ALPHA_TEX_FORMAT();
1779                 } else if(flags & BMP_TEX_ANY){
1780                         BM_SELECT_TEX_FORMAT();                                 
1781                 } else {
1782                         BM_SELECT_SCREEN_FORMAT();
1783                 }
1784
1785                 switch ( be->type ) {
1786                 case BM_TYPE_PCX:
1787                         bm_lock_pcx( handle, bitmapnum, be, bmp, bpp, flags );
1788                         break;
1789
1790                 case BM_TYPE_ANI: 
1791                         bm_lock_ani( handle, bitmapnum, be, bmp, bpp, flags );
1792                         break;
1793
1794                 case BM_TYPE_USER:      
1795                         bm_lock_user( handle, bitmapnum, be, bmp, bpp, flags );
1796                         break;
1797
1798                 case BM_TYPE_TGA:
1799                         bm_lock_tga( handle, bitmapnum, be, bmp, bpp, flags );
1800                         break;
1801
1802                 default:
1803                         Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", be->type );
1804                         return NULL;
1805                 }               
1806
1807                 // always go back to screen format
1808                 BM_SELECT_SCREEN_FORMAT();
1809         }
1810
1811         if ( be->type == BM_TYPE_ANI ) {
1812                 int i,first = bm_bitmaps[bitmapnum].info.ani.first_frame;
1813
1814                 for ( i=0; i< bm_bitmaps[first].info.ani.num_frames; i++ )      {
1815                         // Mark all the bitmaps in this bitmap or animation as recently used
1816                         bm_bitmaps[first+i].last_used = timer_get_milliseconds();
1817
1818                         // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
1819                         #ifdef BMPMAN_NDEBUG
1820                                 bm_bitmaps[first+i].used_count++;
1821                         #endif
1822                         bm_bitmaps[first+i].used_flags = flags;
1823                 }
1824         } else {
1825                 // Mark all the bitmaps in this bitmap or animation as recently used
1826                 be->last_used = timer_get_milliseconds();
1827
1828                 // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
1829                 #ifdef BMPMAN_NDEBUG
1830                         be->used_count++;
1831                 #endif
1832                 be->used_flags = flags;
1833         }
1834
1835         return bmp;
1836 }
1837
1838 // Unlocks a bitmap
1839 //
1840 // Decrements the ref_count member of the bitmap_entry struct.  A bitmap can only be unloaded
1841 // when the ref_count is 0.
1842 //
1843 void bm_unlock( int handle )
1844 {
1845         bitmap_entry    *be;
1846         bitmap                  *bmp;
1847
1848         int bitmapnum = handle % MAX_BITMAPS;
1849         Assert( bm_bitmaps[bitmapnum].handle == handle );       // INVALID BITMAP HANDLE
1850
1851         Assert(bitmapnum >= 0 && bitmapnum < MAX_BITMAPS);
1852         if ( !bm_inited ) bm_init();
1853
1854         be = &bm_bitmaps[bitmapnum];
1855         bmp = &be->bm;
1856
1857         be->ref_count--;
1858         Assert(be->ref_count >= 0);             // Trying to unlock data more times than lock was called!!!
1859
1860 }
1861
1862
1863 void bm_update()
1864 {
1865 }
1866
1867 char *bm_get_filename(int handle)
1868 {
1869         int n;
1870
1871         n = handle % MAX_BITMAPS;
1872         Assert(bm_bitmaps[n].handle == handle);         // INVALID BITMAP HANDLE
1873         return bm_bitmaps[n].filename;
1874 }
1875
1876 void bm_get_palette(int handle, ubyte *pal, char *name)
1877 {
1878         char *filename;
1879         int w,h;
1880
1881         int n= handle % MAX_BITMAPS;
1882         Assert( bm_bitmaps[n].handle == handle );               // INVALID BITMAP HANDLE
1883
1884         filename = bm_bitmaps[n].filename;
1885
1886         if (name)       {
1887                 strcpy( name, filename );
1888         }
1889
1890         int pcx_error=pcx_read_header( filename, &w, &h, pal );
1891         if ( pcx_error != PCX_ERROR_NONE ){
1892                 // Error(LOCATION, "Couldn't open '%s'\n", filename );
1893         }
1894 }
1895
1896 // --------------------------------------------------------------------------------------
1897 // bm_release()  - unloads the bitmap's data and entire slot, so bitmap 'n' won't be valid anymore
1898 //
1899 // parameters:          n               =>              index into bm_bitmaps ( index returned from bm_load() or bm_create() )
1900 //
1901 // returns:                     nothing
1902
1903 // opengl hack
1904 void opengl_free_texture_with_handle(int handle);
1905 void bm_release(int handle)
1906 {
1907         bitmap_entry    *be;
1908
1909         int n = handle % MAX_BITMAPS;
1910
1911         Assert(n >= 0 && n < MAX_BITMAPS);
1912         be = &bm_bitmaps[n];
1913
1914         if ( bm_bitmaps[n].type == BM_TYPE_NONE ) {
1915                 return; // Already been released?
1916         }
1917
1918         if ( bm_bitmaps[n].type != BM_TYPE_USER )       {
1919                 return;
1920         }
1921
1922         Assert( be->handle == handle );         // INVALID BITMAP HANDLE
1923
1924         // If it is locked, cannot free it.
1925         if (be->ref_count != 0) {
1926                 nprintf(("BmpMan", "tried to unload %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
1927                 return;
1928         }
1929
1930 // until opengl mode gets a proper texture manager, this will have to do
1931 #ifdef PLAT_UNIX
1932         opengl_free_texture_with_handle(handle);
1933 #endif
1934
1935         bm_free_data(n);
1936
1937         if ( bm_bitmaps[n].type == BM_TYPE_USER )       {
1938                 bm_bitmaps[n].info.user.data = NULL;
1939                 bm_bitmaps[n].info.user.bpp = 0;
1940         }
1941
1942
1943         bm_bitmaps[n].type = BM_TYPE_NONE;
1944
1945         // Fill in bogus structures!
1946
1947         // For debugging:
1948         strcpy( bm_bitmaps[n].filename, "IVE_BEEN_RELEASED!" );
1949         bm_bitmaps[n].signature = 0xDEADBEEF;                                                                   // a unique signature identifying the data
1950         bm_bitmaps[n].palette_checksum = 0xDEADBEEF;                                                    // checksum used to be sure bitmap is in current palette
1951
1952         // bookeeping
1953         #ifdef BMPMAN_NDEBUG
1954         bm_bitmaps[n].data_size = -1;                                                                   // How much data this bitmap uses
1955         #endif
1956         bm_bitmaps[n].ref_count = -1;                                                                   // Number of locks on bitmap.  Can't unload unless ref_count is 0.
1957
1958         // Bitmap info
1959         bm_bitmaps[n].bm.w = bm_bitmaps[n].bm.h = -1;
1960         
1961         // Stuff needed for animations
1962         // Stuff needed for user bitmaps
1963         memset( &bm_bitmaps[n].info, 0, sizeof(bm_extra_info) );
1964
1965         bm_bitmaps[n].handle = -1;
1966 }
1967
1968
1969
1970
1971
1972
1973 // --------------------------------------------------------------------------------------
1974 // bm_unload()  - unloads the data, but not the bitmap info.
1975 //
1976 // parameters:          n               =>              index into bm_bitmaps ( index returned from bm_load() or bm_create() )
1977 //
1978 // returns:                     0               =>              unload failed
1979 //                                              1               =>              unload successful
1980 //
1981 int bm_unload( int handle )
1982 {
1983         bitmap_entry    *be;
1984         bitmap                  *bmp;
1985
1986         int n = handle % MAX_BITMAPS;
1987
1988         Assert(n >= 0 && n < MAX_BITMAPS);
1989         be = &bm_bitmaps[n];
1990         bmp = &be->bm;
1991
1992         if ( be->type == BM_TYPE_NONE ) {
1993                 return 0;               // Already been released
1994         }
1995
1996         Assert( be->handle == handle );         // INVALID BITMAP HANDLE!
1997
1998         // If it is locked, cannot free it.
1999         if (be->ref_count != 0) {
2000                 nprintf(("BmpMan", "tried to unload %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
2001                 return 0;
2002         }
2003
2004         nprintf(("BmpMan", "unloading %s.  %dx%dx%d\n", be->filename, bmp->w, bmp->h, bmp->bpp));
2005         bm_free_data(n);                // clears flags, bbp, data, etc
2006
2007         return 1;
2008 }
2009
2010
2011 // unload all used bitmaps
2012 void bm_unload_all()
2013 {
2014         int i;
2015
2016         for (i = 0; i < MAX_BITMAPS; i++)       {
2017                 if ( bm_bitmaps[i].type != BM_TYPE_NONE )       {
2018                         bm_unload(bm_bitmaps[i].handle);
2019                 }
2020         }
2021 }
2022
2023
2024 DCF(bmpman,"Shows/changes bitmap caching parameters and usage")
2025 {
2026         if ( Dc_command )       {
2027                 dc_get_arg(ARG_STRING);
2028                 if ( !strcmp( Dc_arg, "flush" ))        {
2029                         dc_printf( "Total RAM usage before flush: %d bytes\n", bm_texture_ram );
2030                         int i;
2031                         for (i = 0; i < MAX_BITMAPS; i++)       {
2032                                 if ( bm_bitmaps[i].type != BM_TYPE_NONE )       {
2033                                         bm_free_data(i);
2034                                 }
2035                         }
2036                         dc_printf( "Total RAM after flush: %d bytes\n", bm_texture_ram );
2037                 } else if ( !strcmp( Dc_arg, "ram" ))   {
2038                         dc_get_arg(ARG_INT);
2039                         Bm_max_ram = Dc_arg_int*1024*1024;
2040                 } else {
2041                         // print usage, not stats
2042                         Dc_help = 1;
2043                 }
2044         }
2045
2046         if ( Dc_help )  {
2047                 dc_printf( "Usage: BmpMan keyword\nWhere keyword can be in the following forms:\n" );
2048                 dc_printf( "BmpMan flush    Unloads all bitmaps.\n" );
2049                 dc_printf( "BmpMan ram x    Sets max mem usage to x MB. (Set to 0 to have no limit.)\n" );
2050                 dc_printf( "\nUse '? BmpMan' to see status of Bitmap manager.\n" );
2051                 Dc_status = 0;  // don't print status if help is printed.  Too messy.
2052         }
2053
2054         if ( Dc_status )        {
2055                 dc_printf( "Total RAM usage: %d bytes\n", bm_texture_ram );
2056
2057
2058                 if ( Bm_max_ram > 1024*1024 )
2059                         dc_printf( "Max RAM allowed: %.1f MB\n", i2fl(Bm_max_ram)/(1024.0f*1024.0f) );
2060                 else if ( Bm_max_ram > 1024 )
2061                         dc_printf( "Max RAM allowed: %.1f KB\n", i2fl(Bm_max_ram)/(1024.0f) );
2062                 else if ( Bm_max_ram > 0 )
2063                         dc_printf( "Max RAM allowed: %d bytes\n", Bm_max_ram );
2064                 else
2065                         dc_printf( "No RAM limit\n" );
2066
2067
2068         }
2069 }
2070
2071 // Marks a texture as being used for this level
2072 void bm_page_in_texture( int bitmapnum, int nframes )
2073 {
2074         int i;
2075         for (i=0; i<nframes;i++ )       {
2076                 int n = bitmapnum % MAX_BITMAPS;
2077
2078                 bm_bitmaps[n+i].preloaded = 1;
2079
2080                 if ( D3D_enabled )      {
2081                         bm_bitmaps[n+i].used_flags = BMP_TEX_OTHER;
2082                 } else {                        
2083                         bm_bitmaps[n+i].used_flags = 0;
2084                 }
2085         }
2086 }
2087
2088 // Marks a texture as being used for this level
2089 // If num_frames is passed, assume this is an animation
2090 void bm_page_in_nondarkening_texture( int bitmapnum, int nframes )
2091 {
2092         int i;
2093         for (i=0; i<nframes;i++ )       {
2094                 int n = bitmapnum % MAX_BITMAPS;
2095
2096                 bm_bitmaps[n+i].preloaded = 4;
2097
2098                 if ( D3D_enabled )      {                       
2099                         bm_bitmaps[n+i].used_flags = BMP_TEX_NONDARK;
2100                 } else {
2101                         bm_bitmaps[n+i].used_flags = 0;
2102                 }
2103         }
2104 }
2105
2106 // marks a texture as being a transparent textyre used for this level
2107 // Marks a texture as being used for this level
2108 // If num_frames is passed, assume this is an animation
2109 void bm_page_in_xparent_texture( int bitmapnum, int nframes)
2110 {
2111         int i;
2112         for (i=0; i<nframes;i++ )       {
2113                 int n = bitmapnum % MAX_BITMAPS;
2114
2115                 bm_bitmaps[n+i].preloaded = 3;
2116
2117                 if ( D3D_enabled )      {
2118                         // bm_bitmaps[n+i].used_flags = BMP_NO_PALETTE_MAP;
2119                         bm_bitmaps[n+i].used_flags = BMP_TEX_XPARENT;
2120                 } else {
2121                         bm_bitmaps[n+i].used_flags = 0;
2122                 }
2123         }
2124 }
2125
2126 // Marks an aabitmap as being used for this level
2127 void bm_page_in_aabitmap( int bitmapnum, int nframes )
2128 {
2129         int i;
2130
2131         for (i=0; i<nframes;i++ )       {
2132                 int n = bitmapnum % MAX_BITMAPS;
2133
2134                 bm_bitmaps[n+i].preloaded = 2;
2135         
2136                 if ( D3D_enabled )      {
2137                         bm_bitmaps[n+i].used_flags = BMP_AABITMAP;
2138                 } else {
2139                         bm_bitmaps[n+i].used_flags = 0;
2140                 }
2141         }
2142 }
2143
2144
2145
2146 // Tell the bitmap manager to start keeping track of what bitmaps are used where.
2147 void bm_page_in_start()
2148 {
2149         int i;
2150
2151         Bm_paging = 1;
2152
2153         // Mark all as inited
2154         for (i = 0; i < MAX_BITMAPS; i++)       {
2155                 if ( bm_bitmaps[i].type != BM_TYPE_NONE )       {
2156                         bm_unload(bm_bitmaps[i].handle);
2157                 }
2158                 bm_bitmaps[i].preloaded = 0;
2159                 #ifdef BMPMAN_NDEBUG
2160                         bm_bitmaps[i].used_count = 0;
2161                 #endif
2162                 bm_bitmaps[i].used_flags = 0;
2163         }
2164
2165 }
2166
2167 #ifndef PLAT_UNIX
2168 extern void gr_d3d_preload_init();
2169 extern int gr_d3d_preload(int bitmap_num, int is_aabitmap );
2170 #endif
2171 extern void gr_opengl_preload_init();
2172 extern int gr_opengl_preload(int bitmap_num, int is_aabitmap );
2173
2174 void bm_page_in_stop()
2175 {       
2176         int i;  
2177         int ship_info_index;
2178
2179         nprintf(( "BmpInfo","BMPMAN: Loading all used bitmaps.\n" ));
2180
2181         // Load all the ones that are supposed to be loaded for this level.
2182         int n = 0;
2183
2184         #ifdef BMPMAN_NDEBUG
2185         Bm_ram_freed = 0;
2186         #endif
2187
2188         int d3d_preloading = 1;
2189
2190 #ifndef PLAT_UNIX
2191         if (gr_screen.mode == GR_DIRECT3D) {
2192                 gr_d3d_preload_init();
2193         } else
2194 #endif  
2195         if (gr_screen.mode == GR_OPENGL) {
2196                 gr_opengl_preload_init();
2197         }
2198
2199         for (i = 0; i < MAX_BITMAPS; i++)       {
2200                 if ( bm_bitmaps[i].type != BM_TYPE_NONE )       {
2201                         if ( bm_bitmaps[i].preloaded )  {
2202 #ifdef BMPMAN_SPECIAL_NONDARK
2203                                 // if this is a texture, check to see if a ship uses it
2204                                 ship_info_index = ship_get_texture(bm_bitmaps[i].handle);
2205                                 // use the colors from this ship
2206                                 if((ship_info_index >= 0) && (Ship_info[ship_info_index].num_nondark_colors > 0)){
2207                                         // mprintf(("Using custom pixels for %s\n", Ship_info[ship_info_index].name));
2208                                         palman_set_nondarkening(Ship_info[ship_info_index].nondark_colors, Ship_info[ship_info_index].num_nondark_colors);
2209                                 }
2210                                 // use the colors from the default table
2211                                 else {
2212                                         // mprintf(("Using default pixels\n"));
2213                                         palman_set_nondarkening(Palman_non_darkening_default, Palman_num_nondarkening_default);
2214                                 }
2215 #endif
2216
2217                                 // if preloaded == 3, load it as an xparent texture                             
2218                                 if(bm_bitmaps[i].used_flags == BMP_AABITMAP){
2219                                         bm_lock( bm_bitmaps[i].handle, 8, bm_bitmaps[i].used_flags );
2220                                 } else {
2221                                         bm_lock( bm_bitmaps[i].handle, 16, bm_bitmaps[i].used_flags );
2222                                 }
2223                                 bm_unlock( bm_bitmaps[i].handle );
2224
2225                                 if ( d3d_preloading )   {
2226 #ifndef PLAT_UNIX
2227                                         if (gr_screen.mode == GR_DIRECT3D) {
2228                                                 if ( !gr_d3d_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded==2) ) )     {
2229                                                         mprintf(( "Out of VRAM.  Done preloading.\n" ));
2230                                                         d3d_preloading = 0;
2231                                                 }
2232                                         } else 
2233 #endif                                  
2234                                         if (gr_screen.mode == GR_OPENGL) {
2235                                                 if ( !gr_opengl_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded==2) ) )  {
2236                                                         mprintf(( "Out of VRAM.  Done preloading.\n" ));
2237                                                         d3d_preloading = 0;
2238                                                 }
2239                                         }
2240                                 }
2241                                 
2242                                 n++;
2243                                 #ifdef BMPMAN_NDEBUG
2244                                 if ( Bm_ram_freed )     {
2245                                         nprintf(( "BmpInfo","BMPMAN: Not enough cache memory to load all level bitmaps\n" ));
2246                                         break;
2247                                 }
2248                                 #endif
2249                         } 
2250                 }
2251                 game_busy();
2252         }
2253         nprintf(( "BmpInfo","BMPMAN: Loaded %d bitmaps that are marked as used for this level.\n", n ));
2254
2255         int total_bitmaps = 0;
2256         for (i = 0; i < MAX_BITMAPS; i++)       {
2257                 if ( bm_bitmaps[i].type != BM_TYPE_NONE )       {
2258                         total_bitmaps++;
2259                 }
2260                 if ( bm_bitmaps[i].type == BM_TYPE_USER )       {
2261                         mprintf(( "User bitmap '%s'\n", bm_bitmaps[i].filename ));
2262                 }
2263         }       
2264
2265         mprintf(( "Bmpman: %d/%d bitmap slots in use.\n", total_bitmaps, MAX_BITMAPS ));
2266         //mprintf(( "Bmpman: Usage went from %d KB to %d KB.\n", usage_before/1024, usage_after/1024 ));
2267
2268         Bm_paging = 0;
2269 }
2270
2271 int bm_get_cache_slot( int bitmap_id, int separate_ani_frames )
2272 {
2273         int n = bitmap_id % MAX_BITMAPS;
2274
2275         Assert( bm_bitmaps[n].handle == bitmap_id );            // INVALID BITMAP HANDLE
2276
2277         bitmap_entry    *be = &bm_bitmaps[n];
2278
2279         if ( (!separate_ani_frames) && (be->type == BM_TYPE_ANI) )      {
2280                 return be->info.ani.first_frame;
2281         } 
2282
2283         return n;
2284
2285 }
2286
2287 // convert a 24 bit value to a 16 bit value
2288 void bm_24_to_16(int bit_24, ushort *bit_16)
2289 {
2290         ubyte *pixel = (ubyte*)&bit_24;
2291         ubyte alpha = 1;
2292
2293         bm_set_components((ubyte*)bit_16, (ubyte*)&pixel[0], (ubyte*)&pixel[1], (ubyte*)&pixel[2], &alpha);     
2294 }
2295
2296 extern int D3D_32bit;
2297
2298 void (*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
2299
2300 void bm_set_components_argb(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2301 {
2302         // rgba 
2303         *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2304         *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2305         *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2306         *((ushort*)pixel) &= ~(0x8000);
2307         if (*((ushort*)pixel) == (ushort)Gr_current_green->mask) {
2308                 *((ushort*)pixel) = 0;
2309         } else {
2310                 if(*av){
2311                         *((ushort*)pixel) |= 0x8000;
2312                 }
2313         }
2314 }
2315
2316 void bm_set_components_d3d(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2317 {
2318         // rgba 
2319         *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2320         *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2321         *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2322         if(*av == 0){ 
2323                 *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2324         }
2325 }
2326
2327 void bm_set_components_argb_d3d_16_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2328 {
2329         *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2330         *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2331         *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2332         if(*av == 0){                           
2333                 *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2334         }                       
2335 }
2336
2337 void bm_set_components_argb_d3d_32_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2338 {
2339         *((uint*)pixel) |= (uint)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2340         *((uint*)pixel) |= (uint)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2341         *((uint*)pixel) |= (uint)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2342         if(*av == 0){                           
2343                 *((uint*)pixel) = (uint)Gr_current_green->mask;         
2344         }
2345 }
2346
2347 void bm_set_components_argb_d3d_16_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2348 {
2349         *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2350         *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2351         *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2352         *((ushort*)pixel) &= ~(Gr_current_alpha->mask);
2353         if(*av){
2354                 *((ushort*)pixel) |= (ushort)(Gr_current_alpha->mask);
2355         } else {
2356                 *((ushort*)pixel) = 0;
2357         }
2358 }
2359
2360 void bm_set_components_argb_d3d_32_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2361 {
2362         *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2363         *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2364         *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2365         *((ushort*)pixel) &= ~(Gr_current_alpha->mask);
2366         if(*av){
2367                 *((ushort*)pixel) |= (ushort)(Gr_current_alpha->mask);
2368         } else {
2369                 *((ushort*)pixel) = 0;
2370         }
2371 }
2372
2373 // for selecting pixel formats
2374 void BM_SELECT_SCREEN_FORMAT()
2375 {
2376         Gr_current_red = &Gr_red;
2377         Gr_current_green = &Gr_green;
2378         Gr_current_blue = &Gr_blue;
2379         Gr_current_alpha = &Gr_alpha;
2380
2381         // setup pointers
2382         if(gr_screen.mode == GR_GLIDE){
2383 #ifndef PLAT_UNIX
2384                 bm_set_components = bm_set_components_argb;
2385 #endif
2386         } else if(gr_screen.mode == GR_DIRECT3D){
2387                 if(Bm_pixel_format == BM_PIXEL_FORMAT_D3D){
2388                         bm_set_components = bm_set_components_d3d;
2389                 } else {
2390                         if(D3D_32bit){
2391                                 bm_set_components = bm_set_components_argb_d3d_32_screen;
2392                         } else {
2393                                 bm_set_components = bm_set_components_argb_d3d_16_screen;
2394                         }
2395                 }
2396         } else if(gr_screen.mode == GR_SOFTWARE){
2397                 bm_set_components = bm_set_components_argb;
2398         } else if(gr_screen.mode == GR_OPENGL){
2399                 bm_set_components = bm_set_components_argb;
2400         }
2401 }
2402
2403 void BM_SELECT_TEX_FORMAT()
2404 {
2405 #ifndef PLAT_UNIX
2406         Gr_current_red = &Gr_t_red; 
2407         Gr_current_green = &Gr_t_green; 
2408         Gr_current_blue = &Gr_t_blue; 
2409         Gr_current_alpha = &Gr_t_alpha;
2410
2411         // setup pointers
2412         if(gr_screen.mode == GR_GLIDE){
2413                 bm_set_components = bm_set_components_argb;
2414         } else
2415 #endif
2416         if(gr_screen.mode == GR_DIRECT3D){
2417                 if(Bm_pixel_format == BM_PIXEL_FORMAT_D3D){
2418                         bm_set_components = bm_set_components_d3d;
2419                 } else {
2420                         if(D3D_32bit){
2421                                 bm_set_components = bm_set_components_argb_d3d_32_tex;
2422                         } else {
2423                                 bm_set_components = bm_set_components_argb_d3d_16_tex;
2424                         }
2425                 }
2426         } else if(gr_screen.mode == GR_SOFTWARE){
2427                 bm_set_components = bm_set_components_argb;
2428         } else if(gr_screen.mode == GR_OPENGL){
2429                 bm_set_components = bm_set_components_argb;
2430         }
2431 }
2432
2433 void BM_SELECT_ALPHA_TEX_FORMAT()
2434 {
2435         Gr_current_red = &Gr_ta_red; 
2436         Gr_current_green = &Gr_ta_green; 
2437         Gr_current_blue = &Gr_ta_blue; 
2438         Gr_current_alpha = &Gr_ta_alpha;
2439
2440         // setup pointers
2441         if(gr_screen.mode == GR_GLIDE){
2442                 bm_set_components = bm_set_components_argb;
2443         } else if(gr_screen.mode == GR_DIRECT3D){
2444                 if(Bm_pixel_format == BM_PIXEL_FORMAT_D3D){
2445                         bm_set_components = bm_set_components_d3d;
2446                 } else {
2447                         if(D3D_32bit){
2448                                 bm_set_components = bm_set_components_argb_d3d_32_tex;
2449                         } else {
2450                                 bm_set_components = bm_set_components_argb_d3d_16_tex;
2451                         }
2452                 }
2453         } else if(gr_screen.mode == GR_SOFTWARE){
2454                 bm_set_components = bm_set_components_argb;
2455         } else if(gr_screen.mode == GR_OPENGL){
2456                 bm_set_components = bm_set_components_argb;
2457         }
2458 }
2459
2460 // set the rgba components of a pixel, any of the parameters can be -1
2461 /*
2462 void bm_set_components(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2463 {
2464         int bit_32 = 0;
2465
2466         // pick a byte size - 32 bits only if 32 bit mode d3d and screen format
2467         if(D3D_32bit && (Gr_current_red == &Gr_red)){
2468                 bit_32 = 1;
2469         }       
2470         
2471         if(bit_32){
2472                 *((uint*)pixel) |= (uint)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2473         } else {
2474                 *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2475         }               
2476         if(bit_32){
2477                 *((uint*)pixel) |= (uint)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2478         } else {
2479                 *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2480         }               
2481         if(bit_32){
2482                 *((uint*)pixel) |= (uint)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2483         } else {
2484                 *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2485         }
2486         
2487         // NOTE - this is a semi-hack. For direct3d we don't use an alpha bit, so if *av == 0, we just set the whole pixel to be Gr_green.mask
2488         //        ergo, we need to do this _last_
2489         switch(Bm_pixel_format){
2490         // glide has an alpha channel so we have to unset ir or set it each time
2491         case BM_PIXEL_FORMAT_ARGB:
2492                 Assert(!bit_32);
2493                 *((ushort*)pixel) &= ~(0x8000);
2494                 if(*av){
2495                         *((ushort*)pixel) |= 0x8000;
2496                 }
2497                 break;
2498         
2499         // this d3d format has no alpha channel, so only make it "transparent", never make it "non-transparent"
2500         case BM_PIXEL_FORMAT_D3D:                       
2501                 Assert(!bit_32);
2502                 if(*av == 0){ 
2503                         *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2504                 }
2505                 break;
2506
2507         // nice 1555 texture format
2508         case BM_PIXEL_FORMAT_ARGB_D3D:                                          
2509                 // if we're writing to normal texture format
2510                 if(Gr_current_red == &Gr_t_red){                                        
2511                         Assert(!bit_32);
2512                         *((ushort*)pixel) &= ~(Gr_current_alpha->mask);
2513                         if(*av){
2514                                 *((ushort*)pixel) |= (ushort)(Gr_current_alpha->mask);
2515                         } else {
2516                                 *((ushort*)pixel) = 0;
2517                         }
2518                 }
2519                 // otherwise if we're writing to screen format, still do it the green mask way
2520                 else {                  
2521                         if(*av == 0){
2522                                 if(bit_32){
2523                                         *((uint*)pixel) = (uint)Gr_current_green->mask;
2524                                 } else {
2525                                         *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2526                                 }
2527                         }
2528                 }                       
2529                 break;
2530         }       
2531 }
2532 */
2533
2534 // get the rgba components of a pixel, any of the parameters can be NULL
2535 void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a)
2536 {
2537         int bit_32 = 0;
2538
2539         // pick a byte size - 32 bits only if 32 bit mode d3d and screen format
2540         if(D3D_32bit && (Gr_current_red == &Gr_red)){
2541                 bit_32 = 1;
2542         }
2543
2544         if(r != NULL){
2545                 if(bit_32){
2546                         *r = ubyte(( (*((uint*)pixel) & Gr_current_red->mask)>>Gr_current_red->shift)*Gr_current_red->scale);
2547                 } else {
2548                         *r = ubyte(( ( ((ushort*)pixel)[0] & Gr_current_red->mask)>>Gr_current_red->shift)*Gr_current_red->scale);
2549                 }
2550         }
2551         if(g != NULL){
2552                 if(bit_32){
2553                         *g = ubyte(( (*((uint*)pixel) & Gr_current_green->mask) >>Gr_current_green->shift)*Gr_current_green->scale);
2554                 } else {
2555                         *g = ubyte(( ( ((ushort*)pixel)[0] & Gr_current_green->mask) >>Gr_current_green->shift)*Gr_current_green->scale);
2556                 }
2557         }
2558         if(b != NULL){
2559                 if(bit_32){
2560                         *b = ubyte(( (*((uint*)pixel) & Gr_current_blue->mask)>>Gr_current_blue->shift)*Gr_current_blue->scale);
2561                 } else {
2562                         *b = ubyte(( ( ((ushort*)pixel)[0] & Gr_current_blue->mask)>>Gr_current_blue->shift)*Gr_current_blue->scale);
2563                 }
2564         }
2565
2566         // get the alpha value
2567         if(a != NULL){          
2568                 *a = 1;
2569
2570                 switch(Bm_pixel_format){
2571                 // glide has an alpha channel so we have to unset ir or set it each time
2572                 case BM_PIXEL_FORMAT_ARGB:                      
2573                         Assert(!bit_32);
2574                         if(!( ((ushort*)pixel)[0] & 0x8000)){
2575                                 *a = 0;
2576                         } 
2577                         break;
2578
2579                 // this d3d format has no alpha channel, so only make it "transparent", never make it "non-transparent"
2580                 case BM_PIXEL_FORMAT_D3D:
2581                         Assert(!bit_32);
2582                         if( *((ushort*)pixel) == Gr_current_green->mask){ 
2583                                 *a = 0;
2584                         }
2585                         break;
2586
2587                 // nice 1555 texture format mode
2588                 case BM_PIXEL_FORMAT_ARGB_D3D:  
2589                         // if we're writing to a normal texture, use nice alpha bits
2590                         if(Gr_current_red == &Gr_t_red){                                
2591                                 Assert(!bit_32);
2592
2593                                 if(!(*((ushort*)pixel) & Gr_current_alpha->mask)){
2594                                         *a = 0;
2595                                 }
2596                         }
2597                         // otherwise do it as normal
2598                         else {
2599                                 if(bit_32){
2600                                         if(*((int*)pixel) == Gr_current_green->mask){ 
2601                                                 *a = 0;
2602                                         }
2603                                 } else {
2604                                         if(*((ushort*)pixel) == Gr_current_green->mask){ 
2605                                                 *a = 0;
2606                                         }
2607                                 }
2608                         }
2609                 }
2610         }
2611 }
2612
2613 // get filename
2614 void bm_get_filename(int bitmapnum, char *filename)
2615 {
2616         int n = bitmapnum % MAX_BITMAPS;
2617
2618         // return filename
2619         strcpy(filename, bm_bitmaps[n].filename);
2620 }
2621
2622 // given a bitmap and a section, return the size (w, h)
2623 void bm_get_section_size(int bitmapnum, int sx, int sy, int *w, int *h)
2624 {
2625         int bw, bh;
2626         bitmap_section_info *sections;
2627
2628         // bogus input?
2629         Assert((w != NULL) && (h != NULL));
2630         if((w == NULL) || (h == NULL)){
2631                 return;
2632         }
2633
2634         // get bitmap info
2635         bm_get_info(bitmapnum, &bw, &bh, NULL, NULL, NULL, &sections);
2636
2637         // determine the width and height of this section
2638         *w = sx < (sections->num_x - 1) ? MAX_BMAP_SECTION_SIZE : bw - sections->sx[sx];
2639         *h = sy < (sections->num_y - 1) ? MAX_BMAP_SECTION_SIZE : bh - sections->sy[sy];                                                                                
2640 }
2641