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