2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Bmpman/BmpMan.cpp $
15 * Code to load and manage all bitmaps for the game
18 * Revision 1.11 2004/07/04 11:31:43 taylor
19 * amd64 support, compiler warning fixes, don't use software rendering
21 * Revision 1.10 2003/05/28 06:02:04 taylor
22 * fix transparency in green weapon blobs
24 * Revision 1.9 2002/06/09 04:41:15 relnev
25 * added copyright header
27 * Revision 1.8 2002/06/05 04:03:32 relnev
28 * finished cfilesystem.
30 * removed some old code.
32 * fixed mouse save off-by-one.
36 * Revision 1.7 2002/06/03 09:25:37 relnev
37 * implement mouse cursor and screen save/restore
39 * Revision 1.6 2002/05/30 23:07:08 relnev
42 * Revision 1.5 2002/05/30 21:44:48 relnev
43 * implemented some missing texture stuff.
45 * enable bitmap polys for opengl.
47 * work around greenness in bitmaps.
49 * Revision 1.4 2002/05/28 17:03:29 theoddone33
50 * fs2 gets to the main game loop now
52 * Revision 1.3 2002/05/28 08:52:03 relnev
53 * implemented two assembly stubs.
55 * cleaned up a few warnings.
57 * added a little demo hackery to make it progress a little farther.
59 * Revision 1.2 2002/05/07 03:16:43 theoddone33
60 * The Great Newline Fix
62 * Revision 1.1.1.1 2002/05/03 03:28:08 root
66 * 37 9/13/99 11:26p Andsager
67 * Add debug code to check for poorly sized anis
69 * 36 9/05/99 11:19p Dave
70 * Made d3d texture cache much more safe. Fixed training scoring bug where
71 * it would backout scores without ever having applied them in the first
74 * 35 8/20/99 2:09p Dave
77 * 34 8/10/99 6:54p Dave
78 * Mad optimizations. Added paging to the nebula effect.
80 * 33 8/06/99 1:52p Dave
81 * Bumped up MAX_BITMAPS for the demo.
83 * 32 8/02/99 1:49p Dave
84 * Fixed low-mem animation problem. Whee!
86 * 31 7/16/99 1:49p Dave
87 * 8 bit aabitmaps. yay.
89 * 30 7/13/99 1:15p Dave
90 * 32 bit support. Whee!
92 * 29 6/29/99 10:35a Dave
93 * Interface polygon bitmaps! Whee!
95 * 28 6/16/99 4:06p Dave
96 * New pilot info popup. Added new draw-bitmap-as-poly function.
98 * 27 5/05/99 9:02p Dave
99 * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
100 * rotations, tweaked values, made bitmap selection more random). Fixed
101 * D3D beam weapon clipping problem. Added D3d frame dumping.
103 * 26 4/27/99 12:16a Dave
104 * Fixed beam weapon muzzle glow problem. Fixed premature timeout on the
105 * pxo server list screen. Fixed secondary firing for hosts on a
106 * standalone. Fixed wacky multiplayer weapon "shuddering" problem.
108 * 25 4/09/99 2:21p Dave
109 * Multiplayer beta stuff. CD checking.
111 * 24 4/08/99 10:42a Johnson
112 * Don't try to swizzle a texture to transparent in Fred.
114 * 23 3/31/99 8:24p Dave
115 * Beefed up all kinds of stuff, incluging beam weapons, nebula effects
116 * and background nebulae. Added per-ship non-dimming pixel colors.
118 * 22 3/20/99 3:46p Dave
119 * Added support for model-based background nebulae. Added 3 new
122 * 21 2/11/99 3:08p Dave
123 * PXO refresh button. Very preliminary squad war support.
125 * 20 2/08/99 5:07p Dave
126 * FS2 chat server support. FS2 specific validated missions.
128 * 19 2/05/99 12:52p Dave
129 * Fixed Glide nondarkening textures.
131 * 18 2/04/99 6:29p Dave
132 * First full working rev of FS2 PXO support. Fixed Glide lighting
135 * 17 2/03/99 11:44a Dave
136 * Fixed d3d transparent textures.
138 * 16 1/15/99 11:29a Neilk
139 * Fixed D3D screen/texture pixel formatting problem.
141 * 15 1/14/99 12:48a Dave
142 * Todo list bug fixes. Made a pass at putting briefing icons back into
143 * FRED. Sort of works :(
145 * 14 1/12/99 12:53a Dave
146 * More work on beam weapons - made collision detection very efficient -
147 * collide against all object types properly - made 3 movement types
148 * smooth. Put in test code to check for possible non-darkening pixels on
151 * 13 1/08/99 2:08p Dave
152 * Fixed software rendering for pofview. Super early support for AWACS and
155 * 12 1/06/99 2:24p Dave
156 * Stubs and release build fixes.
158 * 11 12/14/98 4:01p Dave
159 * Got multi_data stuff working well with new xfer stuff.
161 * 10 12/06/98 2:36p Dave
162 * Drastically improved nebula fogging.
164 * 9 12/01/98 5:53p Dave
165 * Simplified the way pixel data is swizzled. Fixed tga bitmaps to work
166 * properly in D3D and Glide.
168 * 8 12/01/98 4:46p Dave
169 * Put in targa bitmap support (16 bit).
171 * 7 12/01/98 10:32a Johnson
172 * Fixed direct3d font problems. Fixed sun bitmap problem. Fixed direct3d
175 * 6 12/01/98 8:06a Dave
176 * Temporary checkin to fix some texture transparency problems in d3d.
178 * 5 11/30/98 5:31p Dave
179 * Fixed up Fred support for software mode.
181 * 4 11/30/98 1:07p Dave
182 * 16 bit conversion, first run.
184 * 3 10/22/98 6:14p Dave
185 * Optimized some #includes in Anim folder. Put in the beginnings of
186 * parse/localization support for externalized strings and tstrings.tbl
188 * 2 10/07/98 10:52a Dave
191 * 1 10/07/98 10:48a Dave
193 * 106 5/23/98 4:43p John
194 * Took out debugging sleep
196 * 105 5/23/98 4:14p John
197 * Added code to preload textures to video card for AGP. Added in code
198 * to page in some bitmaps that weren't getting paged in at level start.
200 * 104 5/20/98 12:59p John
201 * Turned optimizations on for debug builds. Also turning on automatic
202 * function inlining. Turned off the unreachable code warning.
204 * 103 5/20/98 10:20a Hoffoss
205 * Fixed warning in the code.
207 * 102 5/19/98 3:45p John
208 * fixed bug causing lowmem to drop half of the frames. Also halved fps
211 * 101 5/14/98 3:38p John
212 * Added in more non-darkening colors for Adam. Had to fix some bugs in
213 * BmpMan and Ani stuff to get this to work.
215 * 100 4/22/98 9:13p John
216 * Added code to replace frames of animations in vram if so desired.
218 * 99 4/17/98 6:56a John
219 * Fixed bug where RLE'd user bitmaps caused data to not get freed.
220 * (Turned off RLE for use bitmaps). Made lossy animations reduce
221 * resolution by a factor of 2 in low memory conditions.
223 * 98 4/16/98 6:31p Hoffoss
224 * Added function to get filename of a bitmap handle, which we don't have
227 * 97 4/01/98 9:27p John
228 * Fixed debug info in bmpman.
230 * 96 4/01/98 5:34p John
231 * Made only the used POFs page in for a level. Reduced some interp
232 * arrays. Made custom detail level work differently.
234 * 95 3/31/98 9:55a Lawrance
235 * JOHN: get xparency working for user bitmaps
237 * 94 3/30/98 4:02p John
238 * Made machines with < 32 MB of RAM use every other frame of certain
239 * bitmaps. Put in code to keep track of how much RAM we've malloc'd.
241 * 93 3/29/98 4:05p John
242 * New paging code that loads everything necessary at level startup.
244 * 92 3/27/98 11:20a John
245 * commented back in some debug code.
247 * 91 3/26/98 5:21p John
248 * Added new code to preload all bitmaps at the start of a level.
249 * Commented it out, though.
251 * 90 3/26/98 4:56p Jasen
252 * AL: Allow find_block_of() to allocate a series of bitmaps from index 0
254 * 89 3/26/98 10:21a John
255 * Made no palette-mapped bitmaps use 0,255,0 as transparent.
257 * 88 3/24/98 5:39p John
258 * Added debug code to show bitmap fragmentation. Made user bitmaps
259 * allocate from top of array.
261 * 87 3/22/98 3:28p John
262 * Added in stippled alpha for lower details. Made medium detail use
265 * 86 3/11/98 1:55p John
268 * 85 3/06/98 4:09p John
269 * Changed the way we do bitmap RLE'ing... this speds up HUD bitmaps by
272 * 84 3/02/98 6:00p John
273 * Moved MAX_BITMAPS into BmpMan.h so the stuff in the graphics code that
274 * is dependent on it won't break if it changes. Made ModelCache slots
275 * be equal to MAX_OBJECTS which is what it is.
277 * 83 3/02/98 9:51a John
278 * Added code to print the number of bitmap slots in use between levels.
280 * 82 2/16/98 3:54p John
281 * Changed a bunch of mprintfs to catagorize to BmpInfo
283 * 81 2/13/98 5:00p John
284 * Made user bitmaps not get wrote to level cache file.
286 * 80 2/06/98 8:25p John
287 * Added code for new bitmaps since last frame
289 * 79 2/06/98 8:10p John
290 * Added code to show amout of texture usage each frame.
292 * 78 2/05/98 9:21p John
293 * Some new Direct3D code. Added code to monitor a ton of stuff in the
296 * 77 1/29/98 11:48a John
297 * Added new counter measure rendering as model code. Made weapons be
298 * able to have impact explosion.
300 * 76 1/28/98 6:19p Dave
301 * Reduced standalone memory usage ~8 megs. Put in support for handling
302 * multiplayer submenu handling for endgame, etc.
304 * 75 1/17/98 12:55p John
305 * Fixed bug that I just created that loaded all ani frames.
307 * 74 1/17/98 12:33p John
308 * Made the game_busy function be called a constant amount of times per
309 * level load, making the bar prediction easier.
311 * 73 1/17/98 12:14p John
312 * Added loading... bar to freespace.
314 * 72 1/11/98 3:20p John
315 * Made so that if no .clt exists, it will load all the bitmaps
317 * 71 1/11/98 3:06p John
318 * Made bitmap loading stop when cache gets full.
320 * 70 1/11/98 2:45p John
321 * Changed .lst to .clt
323 * 69 1/11/98 2:14p John
324 * Changed a lot of stuff that had to do with bitmap loading. Made cfile
325 * not do callbacks, I put that in global code. Made only bitmaps that
326 * need to load for a level load.
328 * 67 1/09/98 4:07p John
329 * Made all bitmap functions return a bitmap "Handle" not number. This
330 * helps to find bm_release errors.
332 * 66 1/09/98 1:38p John
333 * Fixed some bugs from previous comment
335 * 65 1/09/98 1:32p John
336 * Added some debugging code to track down a weird error. Namely I fill
337 * in the be structure with bogus values when someone frees it.
339 * 64 12/28/97 2:00p John
340 * put in another assert checking for invalid lock/unlock sequencing
342 * 63 12/24/97 2:02p John
343 * Changed palette translation to be a little faster for unoptimized
346 * 62 12/18/97 8:59p Dave
347 * Finished putting in basic support for weapon select and ship select in
350 * 61 12/15/97 10:27p John
351 * fixed bug where 2 bm_loads of same file both open the header.
353 * 60 12/08/97 2:17p John
354 * fixed bug with bmpman and cf_callback.
355 * made cf_callback in Freespace set small font back when done.
357 * 59 12/03/97 5:01p Lawrance
358 * bump up MAX_BITMAPS to 1500. People have reached 1000 bitmaps while
359 * playing multiple missions.
361 * 58 12/02/97 3:59p John
362 * Added first rev of thruster glow, along with variable levels of
363 * translucency, which retquired some restructing of palman.
365 * 57 11/30/97 3:57p John
366 * Made fixed 32-bpp translucency. Made BmpMan always map translucent
367 * color into 255 even if you aren't supposed to remap and make it's
370 * 56 10/05/97 10:39a John
371 * fixed bug with palette on unmapped bitmaps. Made unmapped bitmaps get
372 * marked with xparent.
374 * 55 9/23/97 11:46a Lawrance
375 * fixed bug with rle'ing with spans get big
377 * 54 9/23/97 10:45a John
378 * made so you can tell bitblt code to rle a bitmap by passing flag to
381 * 53 9/19/97 10:18a John
382 * fixed bug with aa animations being re-rle'd every
386 * 52 9/09/97 10:08a Sandeep
387 * Fixed Compiler Level 4 warnings
389 * 51 9/08/97 2:02p John
390 * fixed typo in nprintf
392 * 50 9/08/97 1:56p John
393 * fixed some memory housekeeping bugs
395 * 49 9/03/97 4:19p John
396 * changed bmpman to only accept ani and pcx's. made passing .pcx or .ani
397 * to bm_load functions not needed. Made bmpman keep track of palettes
398 * for bitmaps not mapped into game palettes.
400 * 48 8/29/97 7:35p Lawrance
401 * check if .ani animation is already loaded in bm_load_animation()
403 * 47 8/25/97 11:14p Lawrance
404 * added support for .ani files in bm_load_animation()
406 * 46 8/17/97 2:42p Lawrance
407 * only flag PCX files as xparent if they have xparent pixels in them
409 * 45 8/15/97 9:57a Lawrance
410 * support multiple xparent entries for PCX files
412 * 44 8/05/97 10:18a Lawrance
413 * my_rand() being used temporarily instead of rand()
415 * 43 8/01/97 4:30p John
417 * 42 7/29/97 8:34a John
420 * 41 7/18/97 3:27p Lawrance
421 * have pcx files use (0,255,0) for transparency
423 * 40 7/16/97 3:07p John
425 * 39 7/10/97 8:34a John
426 * Added code to read TGA files.
428 * 38 6/20/97 1:50p John
429 * added rle code to bmpman. made gr8_aabitmap use it.
431 * 37 6/18/97 12:07p John
432 * fixed some color bugs
434 * 36 6/17/97 8:58p Lawrance
435 * fixed bug with not nulling bm.data with USER bitmaps
437 * 35 6/12/97 2:44a Lawrance
438 * changed bm_unlock() to take an index into bm_bitmaps(). Added
439 * ref_count to bitmap_entry struct
441 * 34 5/20/97 10:36a John
442 * Fixed problem with user bitmaps and direct3d caching.
444 * 33 5/14/97 1:59p John
445 * fixed a palette bug with vclips.
447 * 32 3/24/97 4:43p John
448 * speed up chunked collision detection by only checking cubes the vector
451 * 31 3/24/97 3:25p John
452 * Cleaned up and restructured model_collide code and fvi code. In fvi
453 * made code that finds uvs work.. Added bm_get_pixel to BmpMan.
455 * 30 3/11/97 2:49p Allender
457 * 29 2/18/97 9:43a Lawrance
458 * added Assert() in bm_release
460 * 28 1/22/97 4:29p John
461 * maybe fixed bug with code that counts total bytes of texture ram used.
463 * 27 1/22/97 4:19p Lawrance
464 * added flags to bm_create to allow transparency
466 * 26 1/21/97 5:24p John
467 * fixed another bug with bm_release.
469 * 25 1/21/97 5:12p John
470 * fixed bug with case
472 * 24 1/21/97 5:02p John
473 * Added code for 8bpp user bitmaps.
475 * 23 1/09/97 11:35a John
476 * Added some 2d functions to get/put screen images.
478 * 22 11/26/96 6:50p John
479 * Added some more hicolor primitives. Made windowed mode run as current
480 * bpp, if bpp is 8,16,or 32.
482 * 21 11/26/96 9:44a Allender
483 * Allow for use of different bitmap palettes
485 * 20 11/25/96 10:36a Allender
486 * started working on 32 bpp support. Added 15 bpp.
488 * 19 11/18/96 1:51p Allender
489 * fix up manager code to reread bitmaps if needed in newer bit depth
491 * 18 11/15/96 4:24p Allender
492 * more bmpman stuff -- only free bitmap slots when releasing copied
493 * texture -- otherwise, only release the data for the bitmap
495 * 17 11/15/96 3:33p Allender
496 * added support for converting to 16 bit textures when requested with
497 * bm_load. Added some other management functions
499 * 16 11/13/96 4:51p Allender
500 * started overhaul of bitmap manager. bm_load no longer actually load
501 * the data, only the info for the bitmap. Locking the bitmap now forces
502 * load when no data present (or will if bpp changes)
509 #include "pcxutils.h"
513 #include "animplay.h"
515 #include "systemvars.h"
517 #include "packunpack.h"
519 #include "grinternal.h"
520 #include "tgautils.h"
524 #define BMPMAN_NDEBUG
527 // keep this defined to use per-ship nondarkening pixels
528 #define BMPMAN_SPECIAL_NONDARK
532 #define BM_TYPE_NONE 0
533 #define BM_TYPE_PCX 1
534 #define BM_TYPE_USER 2
535 #define BM_TYPE_ANI 3 // in-house ANI format
536 #define BM_TYPE_TGA 4 // 16 bit targa
538 typedef union bm_extra_info {
540 // Stuff needed for animations
541 int first_frame; // used for animations -- points to index of first frame
542 ubyte num_frames; // used for animation -- number of frames in the animation
543 ubyte fps; // used for animation -- frames per second
546 // Stuff needed for user bitmaps
547 void *data; // For user bitmaps, this is where the data comes from
548 ubyte bpp; // For user bitmaps, this is what format the data is
549 ubyte flags; // Flags passed to bm_create
553 typedef struct bitmap_entry {
555 char filename[MAX_FILENAME_LEN]; // filename for this bitmap
557 uint signature; // a unique signature identifying the data
558 uint palette_checksum; // checksum used to be sure bitmap is in current palette
559 int handle; // Handle = id*MAX_BITMAPS + bitmapnum
560 int last_used; // When this bitmap was last used
562 ubyte type; // PCX, USER, ANI, etc
563 signed char ref_count; // Number of locks on bitmap. Can't unload unless ref_count is 0.
565 // Stuff to keep track of usage
566 ubyte preloaded; // If set, then this was loaded from the lst file
567 ubyte used_flags; // What flags it was accessed thru
572 // Data for animations and user bitmaps
577 ubyte used_last_frame; // If set, then it was used last frame
578 ubyte used_this_frame; // If set, then it was used this frame
579 int data_size; // How much data this bitmap uses
580 int used_count; // How many times it was accessed
584 uint Bm_next_signature = 0x1234;
586 bitmap_entry bm_bitmaps[MAX_BITMAPS];
588 int bm_texture_ram = 0;
590 // Bm_max_ram - How much RAM bmpman can use for textures.
591 // Set to <1 to make it use all it wants.
592 int Bm_max_ram = 0; //16*1024*1024; // Only use 16 MB for textures
594 int bm_next_handle = 1;
598 static int Bm_low_mem = 0;
600 // 16 bit pixel formats
601 int Bm_pixel_format = BM_PIXEL_FORMAT_ARGB;
603 // get and put functions for 16 bit pixels - neat bit slinging, huh?
604 #define BM_SET_R_ARGB(p, r) { p[1] &= ~(0x7c); p[1] |= ((r & 0x1f) << 2); }
605 #define BM_SET_G_ARGB(p, g) { p[0] &= ~(0xe0); p[1] &= ~(0x03); p[0] |= ((g & 0x07) << 5); p[1] |= ((g & 0x18) >> 3); }
606 #define BM_SET_B_ARGB(p, b) { p[0] &= ~(0x1f); p[0] |= b & 0x1f; }
607 #define BM_SET_A_ARGB(p, a) { p[1] &= ~(0x80); p[1] |= ((a & 0x01) << 7); }
609 #define BM_SET_R_D3D(p, r) { *p |= (ushort)(( (int)r / Gr_current_red->scale ) << Gr_current_red->shift); }
610 #define BM_SET_G_D3D(p, g) { *p |= (ushort)(( (int)g / Gr_current_green->scale ) << Gr_current_green->shift); }
611 #define BM_SET_B_D3D(p, b) { *p |= (ushort)(( (int)b / Gr_current_blue->scale ) << Gr_current_blue->shift); }
612 #define BM_SET_A_D3D(p, a) { if(a == 0){ *p = (ushort)Gr_current_green->mask; } }
614 #define BM_SET_R(p, r) { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_R_ARGB(((char*)p), r); break; case BM_PIXEL_FORMAT_D3D: BM_SET_R_D3D(p, r); break; default: Int3(); } }
615 #define BM_SET_G(p, g) { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_G_ARGB(((char*)p), g); break; case BM_PIXEL_FORMAT_D3D: BM_SET_G_D3D(p, g); break; default: Int3(); } }
616 #define BM_SET_B(p, b) { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_B_ARGB(((char*)p), b); break; case BM_PIXEL_FORMAT_D3D: BM_SET_B_D3D(p, b); break; default: Int3(); } }
617 #define BM_SET_A(p, a) { switch(Bm_pixel_format){ case BM_PIXEL_FORMAT_ARGB: BM_SET_A_ARGB(((char*)p), a); break; case BM_PIXEL_FORMAT_D3D: BM_SET_A_D3D(p, a); break; default: Int3(); } }
619 // ===========================================
620 // Mode: 0 = High memory
621 // 1 = Low memory ( every other frame of ani's)
622 // 2 = Debug low memory ( only use first frame of each ani )
623 void bm_set_low_mem( int mode )
625 Assert( (mode >= 0) && (mode<=2 ));
630 static int bm_get_next_handle()
632 int n = bm_next_handle;
634 if ( bm_next_handle > 30000 ) {
640 // Frees a bitmaps data if it should, and
641 // Returns true if bitmap n can free it's data.
642 static void bm_free_data(int n)
647 Assert( n >= 0 && n < MAX_BITMAPS );
652 // If there isn't a bitmap in this structure, don't
653 // do anything but clear out the bitmap info
654 if ( be->type==BM_TYPE_NONE)
657 // If this bitmap doesn't have any data to free, skip
658 // the freeing it part of this.
659 if ( bmp->data == 0 )
662 // Don't free up memory for user defined bitmaps, since
663 // BmpMan isn't the one in charge of allocating/deallocing them.
664 if ( ( be->type==BM_TYPE_USER ) )
667 // Free up the data now!
669 // mprintf(( "Bitmap %d freed %d bytes\n", n, bm_bitmaps[n].data_size ));
671 bm_texture_ram -= be->data_size;
673 free((void *)bmp->data);
677 // Clear out & reset the bitmap data structure
685 be->signature = Bm_next_signature++;
691 int Bm_ram_freed = 0;
693 static void bm_free_some_ram( int n, int size )
696 if ( Bm_max_ram < 1 ) return;
697 if ( bm_texture_ram + size < Bm_max_ram ) return;
699 int current_time = timer_get_milliseconds();
701 while( bm_texture_ram + size > Bm_max_ram ) {
704 // Need to free some RAM up!
705 int i, oldest=-1, best_val=0;
706 for (i = 0; i < MAX_BITMAPS; i++) {
707 if ( (bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].first_frame!=bm_bitmaps[n].first_frame) && (bm_bitmaps[i].ref_count==0) && (bm_bitmaps[i].data_size>0) ) {
708 int page_func = ( current_time-bm_bitmaps[i].last_used)*bm_bitmaps[i].data_size;
709 if ( (oldest==-1) || (page_func>best_val) ) {
711 best_val = page_func;
717 //mprintf(( "Freeing bitmap '%s'\n", bm_bitmaps[oldest].filename ));
718 for (i=0; i<bm_bitmaps[oldest].num_frames; i++ ) {
719 bm_free_data(bm_bitmaps[oldest].first_frame+i);
722 //mprintf(( "Couldn't free enough! %d\n", bm_texture_ram ));
731 static void *bm_malloc( int n, int size )
733 Assert( n >= 0 && n < MAX_BITMAPS );
734 // mprintf(( "Bitmap %d allocated %d bytes\n", n, size ));
736 bm_free_some_ram( n, size );
737 Assert( bm_bitmaps[n].data_size == 0 );
738 bm_bitmaps[n].data_size += size;
739 bm_texture_ram += size;
748 for (i=0; i<MAX_BITMAPS; i++ ) {
749 bm_free_data(i); // clears flags, bbp, data, etc
760 mprintf(( "Size of bitmap info = %d KB\n", sizeof( bm_bitmaps )/1024 ));
761 mprintf(( "Size of bitmap extra info = %d bytes\n", sizeof( bm_extra_info ) ));
768 for (i=0; i<MAX_BITMAPS; i++ ) {
769 bm_bitmaps[i].filename[0] = '\0';
770 bm_bitmaps[i].type = BM_TYPE_NONE;
771 bm_bitmaps[i].info.user.data = NULL;
772 bm_bitmaps[i].bm.data = 0;
773 bm_bitmaps[i].bm.palette = NULL;
775 bm_bitmaps[i].data_size = 0;
776 bm_bitmaps[i].used_count = 0;
777 bm_bitmaps[i].used_last_frame = 0;
778 bm_bitmaps[i].used_this_frame = 0;
780 bm_free_data(i); // clears flags, bbp, data, etc
788 // Returns number of bytes of bitmaps locked this frame
789 // ntotal = number of bytes of bitmaps locked this frame
790 // nnew = number of bytes of bitmaps locked this frame that weren't locked last frame
791 void bm_get_frame_usage(int *ntotal, int *nnew)
798 for (i=0; i<MAX_BITMAPS; i++ ) {
799 if ( (bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].used_this_frame)) {
800 if ( !bm_bitmaps[i].used_last_frame ) {
801 *nnew += bm_bitmaps[i].bm.w*bm_bitmaps[i].bm.h;
803 *ntotal += bm_bitmaps[i].bm.w*bm_bitmaps[i].bm.h;
805 bm_bitmaps[i].used_last_frame = bm_bitmaps[i].used_this_frame;
806 bm_bitmaps[i].used_this_frame = 0;
811 void bm_get_frame_usage(int *ntotal, int *nnew)
816 // given a loaded bitmap with valid info, calculate sections
817 void bm_calc_sections(bitmap *be)
821 // number of x and y sections
822 be->sections.num_x = (ubyte)(be->w / MAX_BMAP_SECTION_SIZE);
823 if((be->sections.num_x * MAX_BMAP_SECTION_SIZE) < be->w){
824 be->sections.num_x++;
826 be->sections.num_y = (ubyte)(be->h / MAX_BMAP_SECTION_SIZE);
827 if((be->sections.num_y * MAX_BMAP_SECTION_SIZE) < be->h){
828 be->sections.num_y++;
831 // calculate the offsets for each section
832 for(idx=0; idx<be->sections.num_x; idx++){
833 be->sections.sx[idx] = (ushort)(MAX_BMAP_SECTION_SIZE * idx);
835 for(idx=0; idx<be->sections.num_y; idx++){
836 be->sections.sy[idx] = (ushort)(MAX_BMAP_SECTION_SIZE * idx);
840 // Creates a bitmap that exists in RAM somewhere, instead
841 // of coming from a disk file. You pass in a pointer to a
842 // block of 32 (or 8)-bit-per-pixel data. Right now, the only
843 // bpp you can pass in is 32 or 8. On success, it returns the
844 // bitmap number. You cannot free that RAM until bm_release
845 // is called on that bitmap.
846 int bm_create( int bpp, int w, int h, void *data, int flags )
848 int i, n, first_slot = MAX_BITMAPS;
855 // Assert((bpp==32)||(bpp==8));
857 Assert(flags & BMP_AABITMAP);
862 if ( !bm_inited ) bm_init();
864 for (i = MAX_BITMAPS-1; i >= 0; i-- ) {
865 if ( bm_bitmaps[i].type == BM_TYPE_NONE ) {
874 // Out of bitmap slots
875 if ( n == -1 ) return -1;
877 memset( &bm_bitmaps[n], 0, sizeof(bitmap_entry) );
879 sprintf( bm_bitmaps[n].filename, "TMP%dx%d", w, h );
880 bm_bitmaps[n].type = BM_TYPE_USER;
881 bm_bitmaps[n].palette_checksum = 0;
883 bm_bitmaps[n].bm.w = short(w);
884 bm_bitmaps[n].bm.h = short(h);
885 bm_bitmaps[n].bm.rowsize = short(w);
886 bm_bitmaps[n].bm.bpp = (unsigned char)(bpp);
887 bm_bitmaps[n].bm.flags = 0;
888 bm_bitmaps[n].bm.flags |= flags;
889 bm_bitmaps[n].bm.data = 0;
890 bm_bitmaps[n].bm.palette = NULL;
892 bm_bitmaps[n].info.user.bpp = ubyte(bpp);
893 bm_bitmaps[n].info.user.data = data;
894 bm_bitmaps[n].info.user.flags = ubyte(flags);
896 bm_bitmaps[n].signature = Bm_next_signature++;
898 bm_bitmaps[n].handle = bm_get_next_handle()*MAX_BITMAPS + n;
899 bm_bitmaps[n].last_used = -1;
901 // fill in section info
902 bm_calc_sections(&bm_bitmaps[n].bm);
904 return bm_bitmaps[n].handle;
907 // sub helper function. Given a raw filename and an extension, try and find the bitmap
908 // returns -1 if it could not be found
909 // 0 if it was found as a file
910 // 1 if it already exists, fills in handle
911 int Bm_ignore_duplicates = 0;
912 int bm_load_sub(const char *real_filename, const char *ext, int *handle)
915 char filename[MAX_FILENAME_LEN] = "";
917 strcpy( filename, real_filename );
918 strcat( filename, ext );
919 for (i=0; i<(int)strlen(filename); i++ ){
920 filename[i] = char(tolower(filename[i]));
923 // try to find given filename to see if it has been loaded before
924 if(!Bm_ignore_duplicates){
925 for (i = 0; i < MAX_BITMAPS; i++) {
926 if ( (bm_bitmaps[i].type != BM_TYPE_NONE) && !stricmp(filename, bm_bitmaps[i].filename) ) {
927 nprintf (("BmpMan", "Found bitmap %s -- number %d\n", filename, i));
928 *handle = bm_bitmaps[i].handle;
934 // try and find the file
936 CFILE *test = cfopen(filename, "rb");
943 // could not be found
947 // This loads a bitmap so we can draw with it later.
948 // It returns a negative number if it couldn't load
949 // the bitmap. On success, it returns the bitmap
950 // number. Function doesn't acutally load the data, only
951 // width, height, and possibly flags.
952 int bm_load( const char * real_filename )
954 int i, n, first_slot = MAX_BITMAPS;
956 char filename[MAX_FILENAME_LEN];
961 if ( !bm_inited ) bm_init();
963 // nice little trick for keeping standalone memory usage way low - always return a bogus bitmap
964 if(Game_mode & GM_STANDALONE_SERVER){
965 strcpy(filename,"test128");
968 // make sure no one passed an extension
969 strcpy( filename, real_filename );
970 char *p = strchr( filename, '.' );
972 mprintf(( "Someone passed an extension to bm_load for file '%s'\n", real_filename ));
977 // try and find the pcx file
978 switch(bm_load_sub(filename, ".pcx", &handle)){
986 strcat(filename, ".pcx");
989 // found as pre-existing
996 // try and find the tga file
997 switch(bm_load_sub(filename, ".tga", &handle)){
1005 strcat(filename, ".tga");
1009 // found as pre-existing
1015 // if its a tga file
1017 int tga_error=targa_read_header( filename, &w, &h, &bpp, NULL );
1018 if ( tga_error != TARGA_ERROR_NONE ) {
1019 mprintf(( "Couldn't open '%s'\n", filename ));
1023 // if its a pcx file
1025 int pcx_error=pcx_read_header( filename, &w, &h, NULL );
1026 if ( pcx_error != PCX_ERROR_NONE ) {
1027 mprintf(( "Couldn't open '%s'\n", filename ));
1032 // Error( LOCATION, "Unknown bitmap type %s\n", filename );
1034 // Find an open slot
1035 for (i = 0; i < MAX_BITMAPS; i++) {
1036 if ( (bm_bitmaps[i].type == BM_TYPE_NONE) && (first_slot == MAX_BITMAPS) ){
1042 Assert( n < MAX_BITMAPS );
1044 if ( n == MAX_BITMAPS ) return -1;
1046 // ensure fields are cleared out from previous bitmap
1047 // Assert(bm_bitmaps[n].bm.data == 0);
1048 // Assert(bm_bitmaps[n].bm.palette == NULL);
1049 // Assert(bm_bitmaps[n].ref_count == 0 );
1050 // Assert(bm_bitmaps[n].user_data == NULL);
1051 memset( &bm_bitmaps[n], 0, sizeof(bitmap_entry) );
1053 // Mark the slot as filled, because cf_read might load a new bitmap
1055 bm_bitmaps[n].type = tga ? (ubyte)BM_TYPE_TGA : (ubyte)BM_TYPE_PCX;
1056 bm_bitmaps[n].signature = Bm_next_signature++;
1057 Assert ( strlen(filename) < MAX_FILENAME_LEN );
1058 strncpy(bm_bitmaps[n].filename, filename, MAX_FILENAME_LEN-1 );
1059 bm_bitmaps[n].bm.w = short(w);
1060 bm_bitmaps[n].bm.rowsize = short(w);
1061 bm_bitmaps[n].bm.h = short(h);
1062 bm_bitmaps[n].bm.bpp = 0;
1063 bm_bitmaps[n].bm.flags = 0;
1064 bm_bitmaps[n].bm.data = 0;
1065 bm_bitmaps[n].bm.palette = NULL;
1067 bm_bitmaps[n].palette_checksum = 0;
1068 bm_bitmaps[n].handle = bm_get_next_handle()*MAX_BITMAPS + n;
1069 bm_bitmaps[n].last_used = -1;
1071 // fill in section info
1072 bm_calc_sections(&bm_bitmaps[n].bm);
1074 return bm_bitmaps[n].handle;
1077 // special load function. basically allows you to load a bitmap which already exists (by filename).
1078 // this is useful because in some cases we need to have a bitmap which is locked in screen format
1079 // _and_ texture format, such as pilot pics and squad logos
1080 int bm_load_duplicate(const char *filename)
1084 // ignore duplicates
1085 Bm_ignore_duplicates = 1;
1088 ret = bm_load(filename);
1091 Bm_ignore_duplicates = 0;
1096 DCF(bm_frag,"Shows BmpMan fragmentation")
1106 for (int i=0; i<MAX_BITMAPS; i++ ) {
1107 switch( bm_bitmaps[i].type ) {
1109 gr_set_color(128,128,128);
1112 gr_set_color(255,0,0);
1115 gr_set_color(0,255,0);
1118 gr_set_color(0,0,255);
1122 gr_rect( x+xs, y+ys, w, h );
1136 static int find_block_of(int n)
1142 for (i=0; i<MAX_BITMAPS; i++ ) {
1143 if ( bm_bitmaps[i].type == BM_TYPE_NONE ) {
1144 if (cnt==0) nstart = i;
1148 if ( cnt == n ) return nstart;
1151 // Error( LOCATION, "Couldn't find block of %d frames\n", n );
1155 // ------------------------------------------------------------------
1156 // bm_load_animation()
1158 // input: filename => filename of animation
1159 // nframes => OUTPUT parameter: number of frames in the animation
1160 // fps => OUTPUT/OPTIONAL parameter: intended fps for the animation
1162 // returns: bitmap number of first frame in the animation
1164 int bm_load_animation( const char *real_filename, int *nframes, int *fps, int can_drop_frames)
1169 char filename[MAX_FILENAME_LEN];
1171 if ( !bm_inited ) bm_init();
1173 strcpy( filename, real_filename );
1174 char *p = strchr( filename, '.' );
1176 mprintf(( "Someone passed an extension to bm_load_animation for file '%s'\n", real_filename ));
1180 strcat( filename, ".ani" );
1182 if ( (fp = cfopen(filename, "rb")) == NULL ) {
1183 // Error(LOCATION,"Could not open filename %s in bm_load_ani()\n", filename);
1189 // for debug of ANI sizes
1190 strcpy(the_anim.name, real_filename);
1192 anim_read_header(&the_anim, fp);
1193 if ( can_drop_frames ) {
1194 if ( Bm_low_mem == 1 ) {
1196 the_anim.total_frames = ( the_anim.total_frames+1)/2;
1197 } else if ( Bm_low_mem == 2 ) {
1198 the_anim.total_frames = 1;
1203 *nframes = the_anim.total_frames;
1204 if ( fps != NULL ) {
1206 *fps = the_anim.fps / 2;
1208 *fps = the_anim.fps;
1212 // first check to see if this ani already has it's frames loaded
1213 for (i = 0; i < MAX_BITMAPS; i++) {
1214 if ( (bm_bitmaps[i].type == BM_TYPE_ANI) && !stricmp(filename, bm_bitmaps[i].filename) ) {
1219 if ( i < MAX_BITMAPS ) {
1220 // in low memory modes this can happen
1222 Assert(bm_bitmaps[i].info.ani.num_frames == *nframes);
1224 return bm_bitmaps[i].handle;
1227 n = find_block_of(*nframes);
1231 // Assert( n >= 0 );
1233 int first_handle = bm_get_next_handle();
1235 Assert ( strlen(filename) < MAX_FILENAME_LEN );
1236 for ( i = 0; i < *nframes; i++ ) {
1237 memset( &bm_bitmaps[n+i], 0, sizeof(bitmap_entry) );
1238 bm_bitmaps[n+i].info.ani.first_frame = n;
1239 bm_bitmaps[n+i].info.ani.num_frames = ubyte(the_anim.total_frames);
1240 bm_bitmaps[n+i].info.ani.fps = ubyte(the_anim.fps);
1241 bm_bitmaps[n+i].bm.w = short(the_anim.width);
1242 bm_bitmaps[n+i].bm.rowsize = short(the_anim.width);
1243 bm_bitmaps[n+i].bm.h = short(the_anim.height);
1245 bm_bitmaps[n+i].bm.w /= 2;
1246 bm_bitmaps[n+i].bm.rowsize /= 2;
1247 bm_bitmaps[n+i].bm.h /= 2;
1249 bm_bitmaps[n+i].bm.flags = 0;
1250 bm_bitmaps[n+i].bm.bpp = 0;
1251 bm_bitmaps[n+i].bm.data = 0;
1252 bm_bitmaps[n+i].bm.palette = NULL;
1253 bm_bitmaps[n+i].type = BM_TYPE_ANI;
1254 bm_bitmaps[n+i].palette_checksum = 0;
1255 bm_bitmaps[n+i].signature = Bm_next_signature++;
1256 bm_bitmaps[n+i].handle = first_handle*MAX_BITMAPS + n+i;
1257 bm_bitmaps[n+i].last_used = -1;
1259 // fill in section info
1260 bm_calc_sections(&bm_bitmaps[n+i].bm);
1263 sprintf( bm_bitmaps[n+i].filename, "%s", filename );
1265 sprintf( bm_bitmaps[n+i].filename, "%s[%d]", filename, i );
1269 return bm_bitmaps[n].handle;
1272 // Gets info. w,h,or flags,nframes or fps can be NULL if you don't care.
1273 void bm_get_info( int handle, int *w, int * h, ubyte * flags, int *nframes, int *fps, bitmap_section_info **sections )
1277 if ( !bm_inited ) return;
1279 int bitmapnum = handle % MAX_BITMAPS;
1280 Assert( bm_bitmaps[bitmapnum].handle == handle ); // INVALID BITMAP HANDLE!
1282 if ( (bm_bitmaps[bitmapnum].type == BM_TYPE_NONE) || (bm_bitmaps[bitmapnum].handle != handle) ) {
1285 if (flags) *flags = 0;
1286 if (nframes) *nframes=0;
1288 if (sections != NULL) *sections = NULL;
1292 bmp = &(bm_bitmaps[bitmapnum].bm);
1296 if (flags) *flags = bmp->flags;
1297 if ( bm_bitmaps[bitmapnum].type == BM_TYPE_ANI ) {
1299 *nframes = bm_bitmaps[bitmapnum].info.ani.num_frames;
1302 *fps= bm_bitmaps[bitmapnum].info.ani.fps;
1312 if(sections != NULL){
1313 *sections = &bm_bitmaps[bitmapnum].bm.sections;
1317 uint bm_get_signature( int handle )
1319 if ( !bm_inited ) bm_init();
1321 int bitmapnum = handle % MAX_BITMAPS;
1322 Assert( bm_bitmaps[bitmapnum].handle == handle ); // INVALID BITMAP HANDLE
1324 return bm_bitmaps[bitmapnum].signature;
1327 extern int palman_is_nondarkening(int r,int g, int b);
1328 static void bm_convert_format( int bitmapnum, bitmap *bmp, ubyte bpp, ubyte flags )
1333 if(Fred_running || Pofview_running || Is_standalone){
1334 Assert(bmp->bpp == 8);
1338 if(flags & BMP_AABITMAP){
1339 Assert(bmp->bpp == 8);
1341 Assert(bmp->bpp == 16);
1345 // maybe swizzle to be an xparent texture
1346 if(!(bmp->flags & BMP_TEX_XPARENT) && (flags & BMP_TEX_XPARENT)){
1347 for(idx=0; idx<bmp->w*bmp->h; idx++){
1349 // if the pixel is transparent
1350 if ( ((ushort*)bmp->data)[idx] == Gr_t_green.mask) {
1351 switch(Bm_pixel_format){
1352 // 1555, all we need to do is zero the whole thing
1353 case BM_PIXEL_FORMAT_ARGB:
1354 case BM_PIXEL_FORMAT_ARGB_D3D:
1355 ((ushort*)bmp->data)[idx] = 0;
1358 case BM_PIXEL_FORMAT_D3D:
1360 r /= Gr_t_red.scale;
1361 g /= Gr_t_green.scale;
1362 b /= Gr_t_blue.scale;
1363 a /= Gr_t_alpha.scale;
1364 ((ushort*)bmp->data)[idx] = (unsigned short)((a<<Gr_t_alpha.shift) | (r << Gr_t_red.shift) | (g << Gr_t_green.shift) | (b << Gr_t_blue.shift));
1372 bmp->flags |= BMP_TEX_XPARENT;
1376 // basically, map the bitmap into the current palette. used to be done for all pcx's, now just for
1377 // Fred, since its the only thing that uses the software tmapper
1378 void bm_swizzle_8bit_for_fred(bitmap_entry *be, bitmap *bmp, ubyte *data, ubyte *palette)
1380 int pcx_xparent_index = -1;
1385 for (i=0; i<256; i++ ) {
1389 if ( g == 255 && r == 0 && b == 0 ) {
1391 pcx_xparent_index = i;
1393 palxlat[i] = (ubyte)(palette_find( r, g, b ));
1396 for (i=0; i<bmp->w * bmp->h; i++ ) {
1397 ubyte c = palxlat[data[i]];
1400 be->palette_checksum = gr_palette_checksum;
1403 void bm_lock_pcx( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1405 ubyte *data, *palette;
1409 // Unload any existing data
1410 bm_free_data( bitmapnum );
1412 // allocate bitmap data
1414 // Assert(Fred_running || Pofview_running || Is_standalone);
1415 data = (ubyte *)bm_malloc(bitmapnum, bmp->w * bmp->h );
1416 #ifdef BMPMAN_NDEBUG
1417 Assert( be->data_size == bmp->w * bmp->h );
1420 bmp->data = (ptr_u)data;
1422 bmp->palette = gr_palette;
1423 memset( data, 0, bmp->w * bmp->h);
1425 data = (ubyte*)bm_malloc(bitmapnum, bmp->w * bmp->h * 2);
1427 bmp->data = (ptr_u)data;
1428 bmp->palette = NULL;
1429 memset( data, 0, bmp->w * bmp->h * 2);
1432 Assert( &be->bm == bmp );
1433 #ifdef BMPMAN_NDEBUG
1434 Assert( be->data_size > 0 );
1437 // some sanity checks on flags
1438 Assert(!((flags & BMP_AABITMAP) && (flags & BMP_TEX_ANY))); // no aabitmap textures
1439 Assert(!((flags & BMP_TEX_XPARENT) && (flags & BMP_TEX_NONDARK))); // can't be a transparent texture and a nondarkening texture
1440 Assert(!((flags & BMP_TEX_NONDARK) && (gr_screen.mode == GR_DIRECT3D))); // D3D should never be trying to get nondarkening textures
1443 int pcx_error=pcx_read_bitmap_8bpp( be->filename, data, palette );
1444 if ( pcx_error != PCX_ERROR_NONE ) {
1445 // Error( LOCATION, "Couldn't open '%s'\n", be->filename );
1446 //Error( LOCATION, "Couldn't open '%s'\n", filename );
1450 // now swizzle the thing into the proper format
1451 if(Fred_running || Pofview_running){
1452 bm_swizzle_8bit_for_fred(be, bmp, data, palette);
1458 if(flags & BMP_AABITMAP){
1459 pcx_error = pcx_read_bitmap_16bpp_aabitmap( be->filename, data );
1460 } else if(flags & BMP_TEX_NONDARK){
1461 pcx_error = pcx_read_bitmap_16bpp_nondark( be->filename, data );
1463 pcx_error = pcx_read_bitmap_16bpp( be->filename, data );
1465 if ( pcx_error != PCX_ERROR_NONE ) {
1466 // Error( LOCATION, "Couldn't open '%s'\n", be->filename );
1467 //Error( LOCATION, "Couldn't open '%s'\n", filename );
1472 #ifdef BMPMAN_NDEBUG
1473 Assert( be->data_size > 0 );
1477 bm_convert_format( bitmapnum, bmp, bpp, flags );
1480 void bm_lock_ani( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1483 anim_instance *the_anim_instance;
1487 int first_frame, nframes;
1489 first_frame = be->info.ani.first_frame;
1490 nframes = bm_bitmaps[first_frame].info.ani.num_frames;
1492 if ( (the_anim = anim_load(bm_bitmaps[first_frame].filename)) == NULL ) {
1493 // Error(LOCATION, "Error opening %s in bm_lock\n", be->filename);
1496 if ( (the_anim_instance = init_anim_instance(the_anim, bpp)) == NULL ) {
1497 // Error(LOCATION, "Error opening %s in bm_lock\n", be->filename);
1498 anim_free(the_anim);
1501 int can_drop_frames = 0;
1503 if ( the_anim->total_frames != bm_bitmaps[first_frame].info.ani.num_frames ) {
1504 can_drop_frames = 1;
1506 bm = &bm_bitmaps[first_frame].bm;
1508 size = bm->w * bm->h * 2;
1510 size = bm->w * bm->h;
1513 for ( i=0; i<nframes; i++ ) {
1514 be = &bm_bitmaps[first_frame+i];
1515 bm = &bm_bitmaps[first_frame+i].bm;
1517 // Unload any existing data
1518 bm_free_data( first_frame+i );
1521 // briefing editor in Fred2 uses aabitmaps (ani's) - force to 8 bit
1522 if(Fred_running || Is_standalone){
1527 bm->data = (ptr_u)bm_malloc(first_frame + i, size);
1529 frame_data = anim_get_next_raw_buffer(the_anim_instance, 0 ,flags & BMP_AABITMAP ? 1 : 0, bm->bpp);
1531 if ( frame_data == NULL ) {
1532 // Error(LOCATION,"Fatal error locking .ani file: %s\n", be->filename);
1538 dptr = (ubyte *)bm->data;
1540 if ( (bm->w!=the_anim->width) || (bm->h!=the_anim->height) ) {
1542 // Int3(); // not ready yet - should only be ingame
1547 fix u, utmp, v, du, dv;
1551 du = ( the_anim->width*F1_0 ) / bm->w;
1552 dv = ( the_anim->height*F1_0 ) / bm->h;
1554 for (h = 0; h < bm->h; h++) {
1555 ubyte *drow = &dptr[bm->w * h];
1556 ubyte *srow = &sptr[f2i(v)*the_anim->width];
1560 for (w = 0; w < bm->w; w++) {
1561 *drow++ = srow[f2i(utmp)];
1570 fix u, utmp, v, du, dv;
1574 du = ( the_anim->width*F1_0 ) / bm->w;
1575 dv = ( the_anim->height*F1_0 ) / bm->h;
1577 for (h = 0; h < bm->h; h++) {
1578 ushort *drow = &((ushort*)dptr)[bm->w * h];
1579 ushort *srow = &((ushort*)sptr)[f2i(v)*the_anim->width];
1583 for (w = 0; w < bm->w; w++) {
1584 *drow++ = srow[f2i(utmp)];
1592 memcpy(dptr, sptr, size);
1595 bm_convert_format( first_frame+i, bm, bpp, flags );
1598 if ( (i < nframes-1) && can_drop_frames ) {
1599 frame_data = anim_get_next_raw_buffer(the_anim_instance, 0, flags & BMP_AABITMAP ? 1 : 0, bm->bpp);
1602 //mprintf(( "Checksum = %d\n", be->palette_checksum ));
1605 free_anim_instance(the_anim_instance);
1606 anim_free(the_anim);
1610 void bm_lock_user( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1615 // Unload any existing data
1616 bm_free_data( bitmapnum );
1618 switch( be->info.user.bpp ) {
1619 case 16: // user 16 bit bitmap
1621 bmp->flags = be->info.user.flags;
1622 bmp->data = (ptr_u)be->info.user.data;
1625 case 8: // Going from 8 bpp to something (probably only for aabitmaps)
1627 Assert(flags & BMP_AABITMAP);
1629 bmp->data = (uint)malloc(bmp->w * bmp->h * 2);
1630 bmp->flags = be->info.user.flags;
1631 bmp->palette = NULL;
1633 // go through and map the pixels
1634 for(idx=0; idx<bmp->w * bmp->h; idx++){
1635 bit_16 = (ushort)((ubyte*)be->info.user.data)[idx];
1636 Assert(bit_16 <= 255);
1638 // stuff the final result
1639 memcpy((char*)bmp->data + (idx * 2), &bit_16, sizeof(ushort));
1642 Assert(flags & BMP_AABITMAP);
1644 bmp->flags = be->info.user.flags;
1645 bmp->data = (ptr_u)be->info.user.data;
1649 // Error( LOCATION, "Unhandled user bitmap conversion from %d to %d bpp", be->info.user.bpp, bmp->bpp );
1652 bm_convert_format( bitmapnum, bmp, bpp, flags );
1655 void bm_lock_tga( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags )
1659 // Unload any existing data
1660 bm_free_data( bitmapnum );
1662 if(Fred_running || Is_standalone){
1668 // should never try to make an aabitmap out of a targa
1669 Assert(!(flags & BMP_AABITMAP));
1671 // allocate bitmap data
1673 data = (ubyte*)bm_malloc(bitmapnum, bmp->w * bmp->h * 2);
1675 data = (ubyte*)bm_malloc(bitmapnum, bmp->w * bmp->h);
1678 bmp->data = (ptr_u)data;
1679 bmp->palette = NULL;
1681 memset( data, 0, bmp->w * bmp->h * 2);
1683 memset( data, 0, bmp->w * bmp->h );
1686 Assert( &be->bm == bmp );
1687 #ifdef BMPMAN_NDEBUG
1688 Assert( be->data_size > 0 );
1691 int tga_error=targa_read_bitmap( be->filename, data, NULL, (bpp == 16) ? 2 : 1);
1692 if ( tga_error != TARGA_ERROR_NONE ) {
1693 // Error( LOCATION, "Couldn't open '%s'\n", be->filename );
1694 //Error( LOCATION, "Couldn't open '%s'\n", filename );
1698 #ifdef BMPMAN_NDEBUG
1699 Assert( be->data_size > 0 );
1703 bm_convert_format( bitmapnum, bmp, bpp, flags );
1706 MONITOR( NumBitmapPage );
1707 MONITOR( SizeBitmapPage );
1709 // This locks down a bitmap and returns a pointer to a bitmap
1710 // that can be accessed until you call bm_unlock. Only lock
1711 // a bitmap when you need it! This will convert it into the
1712 // appropriate format also.
1713 bitmap * bm_lock( int handle, ubyte bpp, ubyte flags )
1719 if ( !bm_inited ) bm_init();
1721 int bitmapnum = handle % MAX_BITMAPS;
1722 Assert( bm_bitmaps[bitmapnum].handle == handle ); // INVALID BITMAP HANDLE
1724 // flags &= (~BMP_RLE);
1726 // if we're on a standalone server, aways for it to lock to 8 bits
1731 // otherwise do it as normal
1733 if(Fred_running || Pofview_running){
1735 Assert( (bm_bitmaps[bitmapnum].type == BM_TYPE_PCX) || (bm_bitmaps[bitmapnum].type == BM_TYPE_ANI) || (bm_bitmaps[bitmapnum].type == BM_TYPE_TGA));
1737 if(flags & BMP_AABITMAP){
1740 Assert( bpp == 16 );
1745 be = &bm_bitmaps[bitmapnum];
1748 // If you hit this assert, chances are that someone freed the
1749 // wrong bitmap and now someone is trying to use that bitmap.
1751 Assert( be->type != BM_TYPE_NONE );
1753 // Increment ref count for bitmap since lock was made on it.
1754 Assert(be->ref_count >= 0);
1755 be->ref_count++; // Lock it before we page in data; this prevents a callback from freeing this
1756 // as it gets read in
1758 // Mark this bitmap as used this frame
1759 #ifdef BMPMAN_NDEBUG
1760 if ( be->used_this_frame < 255 ) {
1761 be->used_this_frame++;
1765 // if bitmap hasn't been loaded yet, then load it from disk
1766 // reread the bitmap from disk under certain conditions
1767 int pal_changed = 0;
1768 int rle_changed = 0;
1769 int fake_xparent_changed = 0;
1770 if ( (bmp->data == 0) || (bpp != bmp->bpp) || pal_changed || rle_changed || fake_xparent_changed ) {
1771 Assert(be->ref_count == 1);
1773 if ( be->type != BM_TYPE_USER ) {
1774 if ( bmp->data == 0 ) {
1775 nprintf (("BmpMan","Loading %s for the first time.\n", be->filename));
1776 } else if ( bpp != bmp->bpp ) {
1777 nprintf (("BmpMan","Reloading %s from bitdepth %d to bitdepth %d\n", be->filename, bmp->bpp, bpp));
1778 } else if ( pal_changed ) {
1779 nprintf (("BmpMan","Reloading %s to remap palette\n", be->filename));
1780 } else if ( rle_changed ) {
1781 nprintf (("BmpMan","Reloading %s to change RLE.\n", be->filename));
1782 } else if ( fake_xparent_changed ) {
1783 nprintf (("BmpMan","Reloading %s to change fake xparency.\n", be->filename));
1787 MONITOR_INC( NumBitmapPage, 1 );
1788 MONITOR_INC( SizeBitmapPage, bmp->w*bmp->h );
1791 if ( be->type != BM_TYPE_USER ) {
1793 strcpy( flag_text, "--" );
1794 nprintf(( "Paging", "Loading %s (%dx%dx%dx%s)\n", be->filename, bmp->w, bmp->h, bpp, flag_text ));
1798 // select proper format
1799 if(flags & BMP_AABITMAP){
1800 BM_SELECT_ALPHA_TEX_FORMAT();
1801 } else if(flags & BMP_TEX_ANY){
1802 BM_SELECT_TEX_FORMAT();
1804 BM_SELECT_SCREEN_FORMAT();
1807 switch ( be->type ) {
1809 bm_lock_pcx( handle, bitmapnum, be, bmp, bpp, flags );
1813 bm_lock_ani( handle, bitmapnum, be, bmp, bpp, flags );
1817 bm_lock_user( handle, bitmapnum, be, bmp, bpp, flags );
1821 bm_lock_tga( handle, bitmapnum, be, bmp, bpp, flags );
1825 Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", be->type );
1829 // always go back to screen format
1830 BM_SELECT_SCREEN_FORMAT();
1833 if ( be->type == BM_TYPE_ANI ) {
1834 int i,first = bm_bitmaps[bitmapnum].info.ani.first_frame;
1836 for ( i=0; i< bm_bitmaps[first].info.ani.num_frames; i++ ) {
1837 // Mark all the bitmaps in this bitmap or animation as recently used
1838 bm_bitmaps[first+i].last_used = timer_get_milliseconds();
1840 // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
1841 #ifdef BMPMAN_NDEBUG
1842 bm_bitmaps[first+i].used_count++;
1844 bm_bitmaps[first+i].used_flags = flags;
1847 // Mark all the bitmaps in this bitmap or animation as recently used
1848 be->last_used = timer_get_milliseconds();
1850 // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
1851 #ifdef BMPMAN_NDEBUG
1854 be->used_flags = flags;
1862 // Decrements the ref_count member of the bitmap_entry struct. A bitmap can only be unloaded
1863 // when the ref_count is 0.
1865 void bm_unlock( int handle )
1870 int bitmapnum = handle % MAX_BITMAPS;
1871 Assert( bm_bitmaps[bitmapnum].handle == handle ); // INVALID BITMAP HANDLE
1873 Assert(bitmapnum >= 0 && bitmapnum < MAX_BITMAPS);
1874 if ( !bm_inited ) bm_init();
1876 be = &bm_bitmaps[bitmapnum];
1880 Assert(be->ref_count >= 0); // Trying to unlock data more times than lock was called!!!
1889 char *bm_get_filename(int handle)
1893 n = handle % MAX_BITMAPS;
1894 Assert(bm_bitmaps[n].handle == handle); // INVALID BITMAP HANDLE
1895 return bm_bitmaps[n].filename;
1898 void bm_get_palette(int handle, ubyte *pal, char *name)
1903 int n= handle % MAX_BITMAPS;
1904 Assert( bm_bitmaps[n].handle == handle ); // INVALID BITMAP HANDLE
1906 filename = bm_bitmaps[n].filename;
1909 strcpy( name, filename );
1912 int pcx_error=pcx_read_header( filename, &w, &h, pal );
1913 if ( pcx_error != PCX_ERROR_NONE ){
1914 // Error(LOCATION, "Couldn't open '%s'\n", filename );
1918 // --------------------------------------------------------------------------------------
1919 // bm_release() - unloads the bitmap's data and entire slot, so bitmap 'n' won't be valid anymore
1921 // parameters: n => index into bm_bitmaps ( index returned from bm_load() or bm_create() )
1926 void opengl_free_texture_with_handle(int handle);
1927 void bm_release(int handle)
1931 int n = handle % MAX_BITMAPS;
1933 Assert(n >= 0 && n < MAX_BITMAPS);
1934 be = &bm_bitmaps[n];
1936 if ( bm_bitmaps[n].type == BM_TYPE_NONE ) {
1937 return; // Already been released?
1940 if ( bm_bitmaps[n].type != BM_TYPE_USER ) {
1944 Assert( be->handle == handle ); // INVALID BITMAP HANDLE
1946 // If it is locked, cannot free it.
1947 if (be->ref_count != 0) {
1948 nprintf(("BmpMan", "tried to unload %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
1952 // until opengl mode gets a proper texture manager, this will have to do
1954 opengl_free_texture_with_handle(handle);
1959 if ( bm_bitmaps[n].type == BM_TYPE_USER ) {
1960 bm_bitmaps[n].info.user.data = NULL;
1961 bm_bitmaps[n].info.user.bpp = 0;
1965 bm_bitmaps[n].type = BM_TYPE_NONE;
1967 // Fill in bogus structures!
1970 strcpy( bm_bitmaps[n].filename, "IVE_BEEN_RELEASED!" );
1971 bm_bitmaps[n].signature = 0xDEADBEEF; // a unique signature identifying the data
1972 bm_bitmaps[n].palette_checksum = 0xDEADBEEF; // checksum used to be sure bitmap is in current palette
1975 #ifdef BMPMAN_NDEBUG
1976 bm_bitmaps[n].data_size = -1; // How much data this bitmap uses
1978 bm_bitmaps[n].ref_count = -1; // Number of locks on bitmap. Can't unload unless ref_count is 0.
1981 bm_bitmaps[n].bm.w = bm_bitmaps[n].bm.h = -1;
1983 // Stuff needed for animations
1984 // Stuff needed for user bitmaps
1985 memset( &bm_bitmaps[n].info, 0, sizeof(bm_extra_info) );
1987 bm_bitmaps[n].handle = -1;
1995 // --------------------------------------------------------------------------------------
1996 // bm_unload() - unloads the data, but not the bitmap info.
1998 // parameters: n => index into bm_bitmaps ( index returned from bm_load() or bm_create() )
2000 // returns: 0 => unload failed
2001 // 1 => unload successful
2003 int bm_unload( int handle )
2008 int n = handle % MAX_BITMAPS;
2010 Assert(n >= 0 && n < MAX_BITMAPS);
2011 be = &bm_bitmaps[n];
2014 if ( be->type == BM_TYPE_NONE ) {
2015 return 0; // Already been released
2018 Assert( be->handle == handle ); // INVALID BITMAP HANDLE!
2020 // If it is locked, cannot free it.
2021 if (be->ref_count != 0) {
2022 nprintf(("BmpMan", "tried to unload %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
2026 nprintf(("BmpMan", "unloading %s. %dx%dx%d\n", be->filename, bmp->w, bmp->h, bmp->bpp));
2027 bm_free_data(n); // clears flags, bbp, data, etc
2033 // unload all used bitmaps
2034 void bm_unload_all()
2038 for (i = 0; i < MAX_BITMAPS; i++) {
2039 if ( bm_bitmaps[i].type != BM_TYPE_NONE ) {
2040 bm_unload(bm_bitmaps[i].handle);
2046 DCF(bmpman,"Shows/changes bitmap caching parameters and usage")
2049 dc_get_arg(ARG_STRING);
2050 if ( !strcmp( Dc_arg, "flush" )) {
2051 dc_printf( "Total RAM usage before flush: %d bytes\n", bm_texture_ram );
2053 for (i = 0; i < MAX_BITMAPS; i++) {
2054 if ( bm_bitmaps[i].type != BM_TYPE_NONE ) {
2058 dc_printf( "Total RAM after flush: %d bytes\n", bm_texture_ram );
2059 } else if ( !strcmp( Dc_arg, "ram" )) {
2060 dc_get_arg(ARG_INT);
2061 Bm_max_ram = Dc_arg_int*1024*1024;
2063 // print usage, not stats
2069 dc_printf( "Usage: BmpMan keyword\nWhere keyword can be in the following forms:\n" );
2070 dc_printf( "BmpMan flush Unloads all bitmaps.\n" );
2071 dc_printf( "BmpMan ram x Sets max mem usage to x MB. (Set to 0 to have no limit.)\n" );
2072 dc_printf( "\nUse '? BmpMan' to see status of Bitmap manager.\n" );
2073 Dc_status = 0; // don't print status if help is printed. Too messy.
2077 dc_printf( "Total RAM usage: %d bytes\n", bm_texture_ram );
2080 if ( Bm_max_ram > 1024*1024 )
2081 dc_printf( "Max RAM allowed: %.1f MB\n", i2fl(Bm_max_ram)/(1024.0f*1024.0f) );
2082 else if ( Bm_max_ram > 1024 )
2083 dc_printf( "Max RAM allowed: %.1f KB\n", i2fl(Bm_max_ram)/(1024.0f) );
2084 else if ( Bm_max_ram > 0 )
2085 dc_printf( "Max RAM allowed: %d bytes\n", Bm_max_ram );
2087 dc_printf( "No RAM limit\n" );
2093 // Marks a texture as being used for this level
2094 void bm_page_in_texture( int bitmapnum, int nframes )
2097 for (i=0; i<nframes;i++ ) {
2098 int n = bitmapnum % MAX_BITMAPS;
2100 bm_bitmaps[n+i].preloaded = 1;
2102 if ( D3D_enabled ) {
2103 bm_bitmaps[n+i].used_flags = BMP_TEX_OTHER;
2105 bm_bitmaps[n+i].used_flags = 0;
2110 // Marks a texture as being used for this level
2111 // If num_frames is passed, assume this is an animation
2112 void bm_page_in_nondarkening_texture( int bitmapnum, int nframes )
2115 for (i=0; i<nframes;i++ ) {
2116 int n = bitmapnum % MAX_BITMAPS;
2118 bm_bitmaps[n+i].preloaded = 4;
2120 if ( D3D_enabled ) {
2121 bm_bitmaps[n+i].used_flags = BMP_TEX_NONDARK;
2123 bm_bitmaps[n+i].used_flags = 0;
2128 // marks a texture as being a transparent textyre used for this level
2129 // Marks a texture as being used for this level
2130 // If num_frames is passed, assume this is an animation
2131 void bm_page_in_xparent_texture( int bitmapnum, int nframes)
2134 for (i=0; i<nframes;i++ ) {
2135 int n = bitmapnum % MAX_BITMAPS;
2137 bm_bitmaps[n+i].preloaded = 3;
2139 if ( D3D_enabled ) {
2140 // bm_bitmaps[n+i].used_flags = BMP_NO_PALETTE_MAP;
2141 bm_bitmaps[n+i].used_flags = BMP_TEX_XPARENT;
2143 bm_bitmaps[n+i].used_flags = 0;
2148 // Marks an aabitmap as being used for this level
2149 void bm_page_in_aabitmap( int bitmapnum, int nframes )
2153 for (i=0; i<nframes;i++ ) {
2154 int n = bitmapnum % MAX_BITMAPS;
2156 bm_bitmaps[n+i].preloaded = 2;
2158 if ( D3D_enabled ) {
2159 bm_bitmaps[n+i].used_flags = BMP_AABITMAP;
2161 bm_bitmaps[n+i].used_flags = 0;
2168 // Tell the bitmap manager to start keeping track of what bitmaps are used where.
2169 void bm_page_in_start()
2175 // Mark all as inited
2176 for (i = 0; i < MAX_BITMAPS; i++) {
2177 if ( bm_bitmaps[i].type != BM_TYPE_NONE ) {
2178 bm_unload(bm_bitmaps[i].handle);
2180 bm_bitmaps[i].preloaded = 0;
2181 #ifdef BMPMAN_NDEBUG
2182 bm_bitmaps[i].used_count = 0;
2184 bm_bitmaps[i].used_flags = 0;
2190 extern void gr_d3d_preload_init();
2191 extern int gr_d3d_preload(int bitmap_num, int is_aabitmap );
2193 extern void gr_opengl_preload_init();
2194 extern int gr_opengl_preload(int bitmap_num, int is_aabitmap );
2196 void bm_page_in_stop()
2199 int ship_info_index;
2201 nprintf(( "BmpInfo","BMPMAN: Loading all used bitmaps.\n" ));
2203 // Load all the ones that are supposed to be loaded for this level.
2206 #ifdef BMPMAN_NDEBUG
2210 int d3d_preloading = 1;
2213 if (gr_screen.mode == GR_DIRECT3D) {
2214 gr_d3d_preload_init();
2217 if (gr_screen.mode == GR_OPENGL) {
2218 gr_opengl_preload_init();
2221 for (i = 0; i < MAX_BITMAPS; i++) {
2222 if ( bm_bitmaps[i].type != BM_TYPE_NONE ) {
2223 if ( bm_bitmaps[i].preloaded ) {
2224 #ifdef BMPMAN_SPECIAL_NONDARK
2225 // if this is a texture, check to see if a ship uses it
2226 ship_info_index = ship_get_texture(bm_bitmaps[i].handle);
2227 // use the colors from this ship
2228 if((ship_info_index >= 0) && (Ship_info[ship_info_index].num_nondark_colors > 0)){
2229 // mprintf(("Using custom pixels for %s\n", Ship_info[ship_info_index].name));
2230 palman_set_nondarkening(Ship_info[ship_info_index].nondark_colors, Ship_info[ship_info_index].num_nondark_colors);
2232 // use the colors from the default table
2234 // mprintf(("Using default pixels\n"));
2235 palman_set_nondarkening(Palman_non_darkening_default, Palman_num_nondarkening_default);
2239 // if preloaded == 3, load it as an xparent texture
2240 if(bm_bitmaps[i].used_flags == BMP_AABITMAP){
2241 bm_lock( bm_bitmaps[i].handle, 8, bm_bitmaps[i].used_flags );
2243 bm_lock( bm_bitmaps[i].handle, 16, bm_bitmaps[i].used_flags );
2245 bm_unlock( bm_bitmaps[i].handle );
2247 if ( d3d_preloading ) {
2249 if (gr_screen.mode == GR_DIRECT3D) {
2250 if ( !gr_d3d_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded==2) ) ) {
2251 mprintf(( "Out of VRAM. Done preloading.\n" ));
2256 if (gr_screen.mode == GR_OPENGL) {
2257 if ( !gr_opengl_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded==2) ) ) {
2258 mprintf(( "Out of VRAM. Done preloading.\n" ));
2265 #ifdef BMPMAN_NDEBUG
2266 if ( Bm_ram_freed ) {
2267 nprintf(( "BmpInfo","BMPMAN: Not enough cache memory to load all level bitmaps\n" ));
2275 nprintf(( "BmpInfo","BMPMAN: Loaded %d bitmaps that are marked as used for this level.\n", n ));
2277 int total_bitmaps = 0;
2278 for (i = 0; i < MAX_BITMAPS; i++) {
2279 if ( bm_bitmaps[i].type != BM_TYPE_NONE ) {
2282 if ( bm_bitmaps[i].type == BM_TYPE_USER ) {
2283 mprintf(( "User bitmap '%s'\n", bm_bitmaps[i].filename ));
2287 mprintf(( "Bmpman: %d/%d bitmap slots in use.\n", total_bitmaps, MAX_BITMAPS ));
2288 //mprintf(( "Bmpman: Usage went from %d KB to %d KB.\n", usage_before/1024, usage_after/1024 ));
2293 int bm_get_cache_slot( int bitmap_id, int separate_ani_frames )
2295 int n = bitmap_id % MAX_BITMAPS;
2297 Assert( bm_bitmaps[n].handle == bitmap_id ); // INVALID BITMAP HANDLE
2299 bitmap_entry *be = &bm_bitmaps[n];
2301 if ( (!separate_ani_frames) && (be->type == BM_TYPE_ANI) ) {
2302 return be->info.ani.first_frame;
2309 // convert a 24 bit value to a 16 bit value
2310 void bm_24_to_16(int bit_24, ushort *bit_16)
2312 ubyte *pixel = (ubyte*)&bit_24;
2315 bm_set_components((ubyte*)bit_16, (ubyte*)&pixel[0], (ubyte*)&pixel[1], (ubyte*)&pixel[2], &alpha);
2318 extern int D3D_32bit;
2320 void (*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
2322 void bm_set_components_argb(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2325 *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2326 *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2327 *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2328 *((ushort*)pixel) &= ~(0x8000);
2329 if (*((ushort*)pixel) == (ushort)Gr_current_green->mask) {
2330 *((ushort*)pixel) = 0;
2333 *((ushort*)pixel) |= 0x8000;
2338 void bm_set_components_d3d(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2341 *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2342 *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2343 *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2345 *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2349 void bm_set_components_argb_d3d_16_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2351 *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2352 *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2353 *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2355 *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2359 void bm_set_components_argb_d3d_32_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2361 *((uint*)pixel) |= (uint)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2362 *((uint*)pixel) |= (uint)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2363 *((uint*)pixel) |= (uint)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2365 *((uint*)pixel) = (uint)Gr_current_green->mask;
2369 void bm_set_components_argb_d3d_16_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2371 *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2372 *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2373 *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2374 *((ushort*)pixel) &= ~(Gr_current_alpha->mask);
2376 *((ushort*)pixel) |= (ushort)(Gr_current_alpha->mask);
2378 *((ushort*)pixel) = 0;
2382 void bm_set_components_argb_d3d_32_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2384 *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2385 *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2386 *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2387 *((ushort*)pixel) &= ~(Gr_current_alpha->mask);
2389 *((ushort*)pixel) |= (ushort)(Gr_current_alpha->mask);
2391 *((ushort*)pixel) = 0;
2395 // for selecting pixel formats
2396 void BM_SELECT_SCREEN_FORMAT()
2398 Gr_current_red = &Gr_red;
2399 Gr_current_green = &Gr_green;
2400 Gr_current_blue = &Gr_blue;
2401 Gr_current_alpha = &Gr_alpha;
2404 if(gr_screen.mode == GR_GLIDE){
2406 bm_set_components = bm_set_components_argb;
2408 } else if(gr_screen.mode == GR_DIRECT3D){
2409 if(Bm_pixel_format == BM_PIXEL_FORMAT_D3D){
2410 bm_set_components = bm_set_components_d3d;
2413 bm_set_components = bm_set_components_argb_d3d_32_screen;
2415 bm_set_components = bm_set_components_argb_d3d_16_screen;
2418 } else if(gr_screen.mode == GR_SOFTWARE){
2419 bm_set_components = bm_set_components_argb;
2420 } else if(gr_screen.mode == GR_OPENGL){
2421 bm_set_components = bm_set_components_argb_d3d_32_screen;
2425 void BM_SELECT_TEX_FORMAT()
2427 Gr_current_red = &Gr_t_red;
2428 Gr_current_green = &Gr_t_green;
2429 Gr_current_blue = &Gr_t_blue;
2430 Gr_current_alpha = &Gr_t_alpha;
2433 if(gr_screen.mode == GR_GLIDE){
2434 bm_set_components = bm_set_components_argb;
2435 } else if(gr_screen.mode == GR_DIRECT3D){
2436 if(Bm_pixel_format == BM_PIXEL_FORMAT_D3D){
2437 bm_set_components = bm_set_components_d3d;
2440 bm_set_components = bm_set_components_argb_d3d_32_tex;
2442 bm_set_components = bm_set_components_argb_d3d_16_tex;
2445 } else if(gr_screen.mode == GR_SOFTWARE){
2446 bm_set_components = bm_set_components_argb;
2447 } else if(gr_screen.mode == GR_OPENGL){
2448 bm_set_components = bm_set_components_argb_d3d_32_tex;
2452 void BM_SELECT_ALPHA_TEX_FORMAT()
2454 Gr_current_red = &Gr_ta_red;
2455 Gr_current_green = &Gr_ta_green;
2456 Gr_current_blue = &Gr_ta_blue;
2457 Gr_current_alpha = &Gr_ta_alpha;
2460 if(gr_screen.mode == GR_GLIDE){
2461 bm_set_components = bm_set_components_argb;
2462 } else if(gr_screen.mode == GR_DIRECT3D){
2463 if(Bm_pixel_format == BM_PIXEL_FORMAT_D3D){
2464 bm_set_components = bm_set_components_d3d;
2467 bm_set_components = bm_set_components_argb_d3d_32_tex;
2469 bm_set_components = bm_set_components_argb_d3d_16_tex;
2472 } else if(gr_screen.mode == GR_SOFTWARE){
2473 bm_set_components = bm_set_components_argb;
2474 } else if(gr_screen.mode == GR_OPENGL){
2475 bm_set_components = bm_set_components_argb_d3d_32_tex;
2479 // set the rgba components of a pixel, any of the parameters can be -1
2481 void bm_set_components(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
2485 // pick a byte size - 32 bits only if 32 bit mode d3d and screen format
2486 if(D3D_32bit && (Gr_current_red == &Gr_red)){
2491 *((uint*)pixel) |= (uint)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2493 *((ushort*)pixel) |= (ushort)(( (int)*rv / Gr_current_red->scale ) << Gr_current_red->shift);
2496 *((uint*)pixel) |= (uint)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2498 *((ushort*)pixel) |= (ushort)(( (int)*gv / Gr_current_green->scale ) << Gr_current_green->shift);
2501 *((uint*)pixel) |= (uint)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2503 *((ushort*)pixel) |= (ushort)(( (int)*bv / Gr_current_blue->scale ) << Gr_current_blue->shift);
2506 // NOTE - this is a semi-hack. For direct3d we don't use an alpha bit, so if *av == 0, we just set the whole pixel to be Gr_green.mask
2507 // ergo, we need to do this _last_
2508 switch(Bm_pixel_format){
2509 // glide has an alpha channel so we have to unset ir or set it each time
2510 case BM_PIXEL_FORMAT_ARGB:
2512 *((ushort*)pixel) &= ~(0x8000);
2514 *((ushort*)pixel) |= 0x8000;
2518 // this d3d format has no alpha channel, so only make it "transparent", never make it "non-transparent"
2519 case BM_PIXEL_FORMAT_D3D:
2522 *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2526 // nice 1555 texture format
2527 case BM_PIXEL_FORMAT_ARGB_D3D:
2528 // if we're writing to normal texture format
2529 if(Gr_current_red == &Gr_t_red){
2531 *((ushort*)pixel) &= ~(Gr_current_alpha->mask);
2533 *((ushort*)pixel) |= (ushort)(Gr_current_alpha->mask);
2535 *((ushort*)pixel) = 0;
2538 // otherwise if we're writing to screen format, still do it the green mask way
2542 *((uint*)pixel) = (uint)Gr_current_green->mask;
2544 *((ushort*)pixel) = (ushort)Gr_current_green->mask;
2553 // get the rgba components of a pixel, any of the parameters can be NULL
2554 void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a)
2558 // pick a byte size - 32 bits only if 32 bit mode d3d and screen format
2559 if(D3D_32bit && (Gr_current_red == &Gr_red)){
2565 *r = ubyte(( (*((uint*)pixel) & Gr_current_red->mask)>>Gr_current_red->shift)*Gr_current_red->scale);
2567 *r = ubyte(( ( ((ushort*)pixel)[0] & Gr_current_red->mask)>>Gr_current_red->shift)*Gr_current_red->scale);
2572 *g = ubyte(( (*((uint*)pixel) & Gr_current_green->mask) >>Gr_current_green->shift)*Gr_current_green->scale);
2574 *g = ubyte(( ( ((ushort*)pixel)[0] & Gr_current_green->mask) >>Gr_current_green->shift)*Gr_current_green->scale);
2579 *b = ubyte(( (*((uint*)pixel) & Gr_current_blue->mask)>>Gr_current_blue->shift)*Gr_current_blue->scale);
2581 *b = ubyte(( ( ((ushort*)pixel)[0] & Gr_current_blue->mask)>>Gr_current_blue->shift)*Gr_current_blue->scale);
2585 // get the alpha value
2589 switch(Bm_pixel_format){
2590 // glide has an alpha channel so we have to unset ir or set it each time
2591 case BM_PIXEL_FORMAT_ARGB:
2593 if(!( ((ushort*)pixel)[0] & 0x8000)){
2598 // this d3d format has no alpha channel, so only make it "transparent", never make it "non-transparent"
2599 case BM_PIXEL_FORMAT_D3D:
2601 if( *((ushort*)pixel) == Gr_current_green->mask){
2606 // nice 1555 texture format mode
2607 case BM_PIXEL_FORMAT_ARGB_D3D:
2608 // if we're writing to a normal texture, use nice alpha bits
2609 if(Gr_current_red == &Gr_t_red){
2612 if(!(*((ushort*)pixel) & Gr_current_alpha->mask)){
2616 // otherwise do it as normal
2619 if(*((int*)pixel) == Gr_current_green->mask){
2623 if(*((ushort*)pixel) == Gr_current_green->mask){
2633 void bm_get_filename(int bitmapnum, char *filename)
2635 int n = bitmapnum % MAX_BITMAPS;
2638 strcpy(filename, bm_bitmaps[n].filename);
2641 // given a bitmap and a section, return the size (w, h)
2642 void bm_get_section_size(int bitmapnum, int sx, int sy, int *w, int *h)
2645 bitmap_section_info *sections;
2648 Assert((w != NULL) && (h != NULL));
2649 if((w == NULL) || (h == NULL)){
2654 bm_get_info(bitmapnum, &bw, &bh, NULL, NULL, NULL, §ions);
2656 // determine the width and height of this section
2657 *w = sx < (sections->num_x - 1) ? MAX_BMAP_SECTION_SIZE : bw - sections->sx[sx];
2658 *h = sy < (sections->num_y - 1) ? MAX_BMAP_SECTION_SIZE : bh - sections->sy[sy];