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