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