FS2_Open
Open source remastering of the Freespace 2 engine
bmpman.cpp
Go to the documentation of this file.
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 the
6  * source.
7  *
8 */
9 #ifndef NDEBUG
10 #define BMPMAN_NDEBUG
11 #endif
12 
13 #define BMPMAN_INTERNAL
14 
15 #ifdef _WIN32
16 #include <windows.h>
17 #endif
18 
19 #include "anim/animplay.h"
20 #include "anim/packunpack.h"
21 #include "bmpman/bm_internal.h"
22 #include "bmpman/bmpman.h"
23 #include "ddsutils/ddsutils.h"
24 #include "debugconsole/console.h"
25 #include "globalincs/systemvars.h"
26 #include "graphics/2d.h"
27 #include "graphics/grinternal.h"
28 #include "io/key.h"
29 #include "io/timer.h"
30 #include "jpgutils/jpgutils.h"
31 #include "network/multiutil.h"
32 #include "palman/palman.h"
33 #include "parse/parselo.h"
34 #include "pcxutils/pcxutils.h"
35 #include "pngutils/pngutils.h"
36 #include "ship/ship.h"
37 #include "tgautils/tgautils.h"
38 
39 #include <ctype.h>
40 #include <limits.h>
41 #include <iomanip>
42 
43 // --------------------------------------------------------------------------------------------------------------------
44 // Private macros.
45 
49 #define EFF_FILENAME_CHECK { if ( be->type == BM_TYPE_EFF ) strcpy_s( filename, be->info.ani.eff.filename ); else strcpy_s( filename, be->filename ); }
50 // --------------------------------------------------------------------------------------------------------------------
51 // Monitor variables
52 MONITOR(NumBitmapPage)
53 MONITOR(SizeBitmapPage)
54 
55 // --------------------------------------------------------------------------------------------------------------------
56 // Definition of public variables (declared as extern in bmpman.h).
57 int GLOWMAP = -1;
58 int SPECMAP = -1;
59 int ENVMAP = -1;
60 int NORMMAP = -1;
61 int HEIGHTMAP = -1;
62 int MISCMAP = -1;
63 
65 int Bm_paging = 0;
66 
67 // Extension type lists
69 const char *bm_ext_list[] = { ".dds", ".tga", ".png", ".jpg", ".pcx" };
70 const int BM_NUM_TYPES = sizeof(bm_type_list) / sizeof(bm_type_list[0]);
71 
73 const char *bm_ani_ext_list[] = { ".eff", ".ani" };
74 const int BM_ANI_NUM_TYPES = sizeof(bm_ani_type_list) / sizeof(bm_ani_type_list[0]);
75 
76 void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
77 void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
78 
79 // --------------------------------------------------------------------------------------------------------------------
80 // Declaration of protected variables (defined in cmdline.cpp).
81 extern int Cmdline_cache_bitmaps;
82 
83 // --------------------------------------------------------------------------------------------------------------------
84 // Definition of public variables (declared as extern in bm_internal.h).
86 
87 // --------------------------------------------------------------------------------------------------------------------
88 // Definition of private variables at file scope (static).
89 static int bm_inited = 0;
90 static uint Bm_next_signature = 0x1234;
91 static int bm_next_handle = 1;
92 static int Bm_low_mem = 0;
93 
101 static int Bm_max_ram = 0;
102 
103 static int Bm_ignore_duplicates = 0;
104 static int Bm_ignore_load_count = 0;
105 
106 // --------------------------------------------------------------------------------------------------------------------
107 // Declaration of private functions and templates(declared as static type func(type param);)
108 
110  Bitmap_data(NULL)
111 {
112  if ( !bm_is_valid(bitmap_num) ) return;
113 
114  Num_channels = 3;
115 
116  if ( bm_has_alpha_channel(bitmap_num) ) {
117  Num_channels = 4;
118  }
119 
120  int n = bitmap_num % MAX_BITMAPS;
121 
122  bitmap_entry *be = &bm_bitmaps[n];
123 
124  Width = be->bm.w;
125  Height = be->bm.h;
126 
127  Bitmap_data = (ubyte*)vm_malloc(Width * Height * Num_channels * sizeof(ubyte));
128 
129  gr_get_bitmap_from_texture((void*)Bitmap_data, bitmap_num);
130 }
131 
133 {
134  if ( Bitmap_data != NULL ) {
135  vm_free(Bitmap_data);
136  }
137 }
138 
140 {
141  return Bitmap_data != NULL;
142 }
143 
144 float bitmap_lookup::map_texture_address(float address)
145 {
146  // assume we're just wrapping
147  return address - floorf(address);
148 }
149 
150 float bitmap_lookup::get_channel_red(float u, float v)
151 {
152  Assert( Bitmap_data != NULL );
153 
154  CLAMP(u, 0.0, 1.0f);
155  CLAMP(v, 0.0, 1.0f);
156 
157  int x = fl2i(map_texture_address(u) * (Width-1));
158  int y = fl2i(map_texture_address(v) * (Height-1));
159 
160  return i2fl(Bitmap_data[(y*Width + x)*Num_channels]) / 255.0f;
161 }
162 
164 {
165  Assert( Bitmap_data != NULL );
166 
167  CLAMP(u, 0.0, 1.0f);
168  CLAMP(v, 0.0, 1.0f);
169 
170  int x = fl2i(map_texture_address(u) * (Width-1));
171  int y = fl2i(map_texture_address(v) * (Height-1));
172 
173  return i2fl(Bitmap_data[(y*Width + x)*Num_channels + 1]) / 255.0f;
174 }
175 
177 {
178  Assert( Bitmap_data != NULL );
179 
180  int x = fl2i(map_texture_address(u) * (Width-1));
181  int y = fl2i(map_texture_address(v) * (Height-1));
182 
183  return i2fl(Bitmap_data[(y*Width + x)*Num_channels + 2]) / 255.0f;
184 }
185 
187 {
188  Assert( Bitmap_data != NULL );
189 
190  int x = fl2i(map_texture_address(u) * (Width-1));
191  int y = fl2i(map_texture_address(v) * (Height-1));
192 
193  return i2fl(Bitmap_data[(y*Width + x)*Num_channels + 3]) / 255.0f;
194 }
195 
199 static void bm_convert_format(bitmap *bmp, ubyte flags);
200 
204 static void bm_free_data(int n, bool release = false);
205 
213 static void bm_free_data_fast(int n);
214 
222 static int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **ext_list, CFILE **img_cfp = NULL, int dir_type = CF_TYPE_ANY);
223 
230 static int bm_load_sub_fast(const char *real_filename, int *handle, int dir_type = CF_TYPE_ANY, bool animated_type = false);
231 
238 static int find_block_of(int n);
239 
240 // --------------------------------------------------------------------------------------------------------------------
241 // Macro-defined functions
242 
243 DCF(bm_frag, "Shows BmpMan fragmentation") {
244  if (dc_optional_string_either("help", "--help")) {
245  dc_printf("Displays a graphic showing the BmpMan fragmentation. Color key:\n");
246  dc_printf("\tGray : NONE\n");
247  dc_printf("\tRed : PCXn");
248  dc_printf("\tGreen : USER, TGA, PNG, DDS, other\n");
249  dc_printf("\tBlue : ANI, EFF\n\n");
250 
251  dc_printf("Once done reviewing the graphic, press any key to return to the console\n");
252  return;
253  }
254 
255  gr_clear();
256 
257  int x = 0, y = 0;
258  int xs = 2, ys = 2;
259  int w = 4, h = 4;
260 
261  for (int i = 0; i<MAX_BITMAPS; i++) {
262  switch (bm_bitmaps[i].type) {
263  case BM_TYPE_NONE:
264  gr_set_color(128, 128, 128);
265  break;
266  case BM_TYPE_PCX:
267  gr_set_color(255, 0, 0);
268  break;
269  case BM_TYPE_USER:
270  case BM_TYPE_TGA:
271  case BM_TYPE_PNG:
272  case BM_TYPE_DDS:
273  gr_set_color(0, 255, 0);
274  break;
275  case BM_TYPE_ANI:
276  case BM_TYPE_EFF:
277  gr_set_color(0, 0, 255);
278  break;
279  default:
280  gr_set_color(0, 255, 0);
281  break;
282  }
283 
284  gr_rect(x + xs, y + ys, w, h);
285  x += w + xs + xs;
286  if (x > 639) {
287  x = 0;
288  y += h + ys + ys;
289  }
290  }
291 
292  gr_flip();
293  key_getch();
294 }
295 
296 DCF(bm_used, "Shows BmpMan Slot Usage") {
297  if (dc_optional_string_either("help", "--help")) {
298  dc_printf("Displays used bmpman slots usage with a breakdown per filetype\n\n");
299  return;
300  }
301 
302  int none = 0, pcx = 0, user = 0, tga = 0, png = 0; int jpg = 0, dds = 0, ani = 0;
303  int eff = 0, eff_dds = 0, eff_tga = 0, eff_png = 0, eff_jpg = 0, eff_pcx = 0;
304  int render_target_dynamic = 0, render_target_static = 0;
305 
306  for (int i = 0; i<MAX_BITMAPS; i++) {
307  switch (bm_bitmaps[i].type) {
308  case BM_TYPE_NONE:
309  none++;
310  break;
311  case BM_TYPE_PCX:
312  pcx++;
313  break;
314  case BM_TYPE_USER:
315  user++;
316  break;
317  case BM_TYPE_TGA:
318  tga++;
319  break;
320  case BM_TYPE_PNG:
321  // TODO distinguish png(static) from apng
322  png++;
323  break;
324  case BM_TYPE_JPG:
325  jpg++;
326  break;
327  case BM_TYPE_DDS:
328  dds++;
329  break;
330  case BM_TYPE_ANI:
331  ani++;
332  break;
333  case BM_TYPE_EFF:
334  eff++;
335  switch (bm_bitmaps[i].info.ani.eff.type) {
336  case BM_TYPE_DDS:
337  eff_dds++;
338  break;
339  case BM_TYPE_TGA:
340  eff_tga++;
341  break;
342  case BM_TYPE_PNG:
343  eff_png++;
344  break;
345  case BM_TYPE_JPG:
346  eff_jpg++;
347  break;
348  case BM_TYPE_PCX:
349  eff_pcx++;
350  break;
351  default:
352  Warning(LOCATION, "Unhandled EFF image type (%i), get a coder!", bm_bitmaps[i].info.ani.eff.type);
353  break;
354  }
355  break;
357  render_target_static++;
358  break;
360  render_target_dynamic++;
361  break;
362  default:
363  Warning(LOCATION, "Unhandled image type (%i), get a coder!", bm_bitmaps[i].type);
364  break;
365  }
366  }
367 
368  SCP_stringstream text;
369  text << "BmpMan Used Slots\n";
370  text << " " << std::dec << std::setw(4) << std::setfill('0') << pcx << ", PCX\n";
371  text << " " << std::dec << std::setw(4) << std::setfill('0') << user << ", User\n";
372  text << " " << std::dec << std::setw(4) << std::setfill('0') << tga << ", TGA\n";
373  text << " " << std::dec << std::setw(4) << std::setfill('0') << png << ", PNG\n";
374  text << " " << std::dec << std::setw(4) << std::setfill('0') << jpg << ", JPG\n";
375  text << " " << std::dec << std::setw(4) << std::setfill('0') << dds << ", DDS\n";
376  text << " " << std::dec << std::setw(4) << std::setfill('0') << ani << ", ANI\n";
377  text << " " << std::dec << std::setw(4) << std::setfill('0') << eff << ", EFF\n";
378  text << " " << std::dec << std::setw(4) << std::setfill('0') << eff_dds << ", EFF/DDS\n";
379  text << " " << std::dec << std::setw(4) << std::setfill('0') << eff_tga << ", EFF/TGA\n";
380  text << " " << std::dec << std::setw(4) << std::setfill('0') << eff_png << ", EFF/PNG\n";
381  text << " " << std::dec << std::setw(4) << std::setfill('0') << eff_jpg << ", EFF/JPG\n";
382  text << " " << std::dec << std::setw(4) << std::setfill('0') << eff_pcx << ", EFF/PCX\n";
383  text << " " << std::dec << std::setw(4) << std::setfill('0') << render_target_static << ", Render/Static\n";
384  text << " " << std::dec << std::setw(4) << std::setfill('0') << render_target_dynamic << ", Render/Dynamic\n";
385  text << " " << std::dec << std::setw(4) << std::setfill('0') << MAX_BITMAPS-none << "/" << MAX_BITMAPS << ", Total\n";
386  text << "\n";
387 
388  // TODO consider converting 1's to monospace to make debug console output prettier
389  mprintf(("%s", text.str().c_str())); // log for ease for copying data
390  dc_printf("%s", text.str().c_str()); // instant gratification
391 }
392 
393 
394 DCF(bmpman, "Shows/changes bitmap caching parameters and usage") {
395  if (dc_optional_string_either("help", "--help")) {
396  dc_printf("Usage: BmpMan [arg]\nWhere arg can be any of the following:\n");
397  dc_printf("\tflush Unloads all bitmaps.\n");
398  dc_printf("\tram [x] Sets max mem usage to x MB. (Set to 0 to have no limit.)\n");
399  dc_printf("\t? Displays status of Bitmap manager.\n");
400  return;
401  }
402 
403  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
404  dc_printf("Total RAM usage: %d bytes\n", bm_texture_ram);
405 
406  if (Bm_max_ram > 1024 * 1024) {
407  dc_printf("\tMax RAM allowed: %.1f MB\n", i2fl(Bm_max_ram) / (1024.0f*1024.0f));
408  } else if (Bm_max_ram > 1024) {
409  dc_printf("\tMax RAM allowed: %.1f KB\n", i2fl(Bm_max_ram) / (1024.0f));
410  } else if (Bm_max_ram > 0) {
411  dc_printf("\tMax RAM allowed: %d bytes\n", Bm_max_ram);
412  } else {
413  dc_printf("\tNo RAM limit\n");
414  }
415  return;
416  }
417 
418 
419  if (dc_optional_string("flush")) {
420  dc_printf("Total RAM usage before flush: %d bytes\n", bm_texture_ram);
421  int i;
422  for (i = 0; i < MAX_BITMAPS; i++) {
423  if (bm_bitmaps[i].type != BM_TYPE_NONE) {
424  bm_free_data(i);
425  }
426  }
427  dc_printf("Total RAM after flush: %d bytes\n", bm_texture_ram);
428  } else if (dc_optional_string("ram")) {
429  dc_stuff_int(&Bm_max_ram);
430 
431  if (Bm_max_ram > 0) {
432  dc_printf("BmpMan limited to %i, MB's\n", Bm_max_ram);
433  Bm_max_ram *= 1024 * 1024;
434  } else if (Bm_max_ram == 0) {
435  dc_printf("!!BmpMan memory is unlimited!!\n");
436  } else {
437  dc_printf("Illegal value. Must be non-negative.");
438  }
439  } else {
440  dc_printf("<BmpMan> No argument given\n");
441  }
442 }
443 
444 DCF(bmpslots, "Writes bitmap slot info to fs2_open.log") {
445  if (dc_optional_string_either("help", "--help")) {
446  dc_printf("Usage: bmpslots\n");
447  dc_printf("\tWrites bitmap slot info to fs2_open.log\n");
448  return;
449  }
451 }
452 
453 // --------------------------------------------------------------------------------------------------------------------
454 // Definition of all functions, in alphabetical order
455 void bm_clean_slot(int n) {
456  bm_free_data(n);
457 }
458 
459 void bm_close() {
460  int i;
461  if (bm_inited) {
462  for (i = 0; i<MAX_BITMAPS; i++) {
463  bm_free_data(i); // clears flags, bbp, data, etc
464  }
465  bm_inited = 0;
466  }
467 }
468 
469 int bm_create(int bpp, int w, int h, void *data, int flags) {
470  if (bpp == 8) {
471  Assert(flags & BMP_AABITMAP);
472  } else {
473  Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
474  }
475 
476  if (!bm_inited) bm_init();
477 
478  int n = -1;
479 
480  for (int i = MAX_BITMAPS - 1; i >= 0; i--) {
481  if (bm_bitmaps[i].type == BM_TYPE_NONE) {
482  n = i;
483  break;
484  }
485  }
486 
487  Assert(n > -1);
488 
489  // Out of bitmap slots
490  if (n == -1)
491  return -1;
492 
493  // make sure that we have valid data
494  if (data == NULL) {
495  Int3();
496  return -1;
497  }
498 
499  memset(&bm_bitmaps[n], 0, sizeof(bitmap_entry));
500 
501  sprintf(bm_bitmaps[n].filename, "TMP%dx%d+%d", w, h, bpp);
502  bm_bitmaps[n].type = BM_TYPE_USER;
503  bm_bitmaps[n].comp_type = BM_TYPE_NONE;
504  bm_bitmaps[n].palette_checksum = 0;
505 
506  bm_bitmaps[n].bm.w = (short)w;
507  bm_bitmaps[n].bm.h = (short)h;
508  bm_bitmaps[n].bm.rowsize = (short)w;
509  bm_bitmaps[n].bm.bpp = (ubyte)bpp;
510  bm_bitmaps[n].bm.flags = (ubyte)flags;
511  bm_bitmaps[n].bm.data = 0;
512  bm_bitmaps[n].bm.palette = NULL;
513 
514  bm_bitmaps[n].info.user.bpp = (ubyte)bpp;
515  bm_bitmaps[n].info.user.data = data;
516  bm_bitmaps[n].info.user.flags = (ubyte)flags;
517 
518  bm_bitmaps[n].signature = Bm_next_signature++;
519 
520  bm_bitmaps[n].handle = bm_get_next_handle() * MAX_BITMAPS + n;
521  bm_bitmaps[n].last_used = -1;
522  bm_bitmaps[n].mem_taken = (w * h * (bpp >> 3));
523 
524  bm_bitmaps[n].load_count++;
525 
526  bm_update_memory_used(n, (int)bm_bitmaps[n].mem_taken);
527 
528  gr_bm_create(n);
529 
530  return bm_bitmaps[n].handle;
531 }
532 
533 void bm_convert_format(bitmap *bmp, ubyte flags) {
534  int idx;
535 
536  // no transparency for 24 bpp images
537  if (!(flags & BMP_AABITMAP) && (bmp->bpp == 24))
538  return;
539 
540  if (Is_standalone) {
541  Assert(bmp->bpp == 8);
542  return;
543  } else {
544  if (flags & BMP_AABITMAP)
545  Assert(bmp->bpp == 8);
546  else
547  Assert((bmp->bpp == 16) || (bmp->bpp == 32));
548  }
549 
550  // maybe swizzle to be an xparent texture
551  if (!(bmp->flags & BMP_TEX_XPARENT) && (flags & BMP_TEX_XPARENT)) {
552  for (idx = 0; idx<bmp->w*bmp->h; idx++) {
553  // if the pixel is transparent
554  if (((ushort*)bmp->data)[idx] == Gr_t_green.mask) {
555  ((ushort*)bmp->data)[idx] = 0;
556  }
557  }
558 
559  bmp->flags |= BMP_TEX_XPARENT;
560  }
561 }
562 
563 void bm_free_data(int n, bool release)
564 {
565  bitmap_entry *be;
566  bitmap *bmp;
567 
568  Assert( (n >= 0) && (n < MAX_BITMAPS) );
569 
570  be = &bm_bitmaps[n];
571  bmp = &be->bm;
572 
573  gr_bm_free_data(n, release);
574 
575  // If there isn't a bitmap in this structure, don't
576  // do anything but clear out the bitmap info
577  if (be->type==BM_TYPE_NONE)
578  goto SkipFree;
579 
580  // Don't free up memory for user defined bitmaps, since
581  // BmpMan isn't the one in charge of allocating/deallocing them.
582  if (be->type==BM_TYPE_USER) {
583 #ifdef BMPMAN_NDEBUG
584  if ( be->data_size != 0 )
585  bm_texture_ram -= be->data_size;
586 #endif
587  goto SkipFree;
588  }
589 
590  // If this bitmap doesn't have any data to free, skip
591  // the freeing it part of this.
592  if (bmp->data == 0) {
593 #ifdef BMPMAN_NDEBUG
594  if ( be->data_size != 0 )
595  bm_texture_ram -= be->data_size;
596 #endif
597  goto SkipFree;
598  }
599 
600  // Free up the data now!
601 #ifdef BMPMAN_NDEBUG
602  bm_texture_ram -= be->data_size;
603 #endif
604  vm_free((void *)bmp->data);
605 
606  // reset the load_count to at least 1, don't do this in SkipFree though
607  // since the real count ends up wrong
608  be->load_count = 1;
609 
610 SkipFree:
611 
612  // Clear out & reset the bitmap data structure
613  bmp->flags = 0;
614  bmp->bpp = 0;
615  bmp->data = 0;
616  bmp->palette = NULL;
617 #ifdef BMPMAN_NDEBUG
618  be->data_size = 0;
619 #endif
620  be->signature = Bm_next_signature++;
621 }
622 
623 void bm_free_data_fast(int n)
624 {
625  bitmap_entry *be;
626  bitmap *bmp;
627 
628  Assert( (n >= 0) && (n < MAX_BITMAPS) );
629 
630  be = &bm_bitmaps[n];
631  bmp = &be->bm;
632 
633  // If there isn't a bitmap in this structure, don't
634  // do anything but clear out the bitmap info
635  if (be->type == BM_TYPE_NONE)
636  return;
637 
638  // Don't free up memory for user defined bitmaps, since
639  // BmpMan isn't the one in charge of allocating/deallocing them.
640  if (be->type == BM_TYPE_USER) {
641 #ifdef BMPMAN_NDEBUG
642  if ( be->data_size != 0 )
643  bm_texture_ram -= be->data_size;
644 #endif
645  return;
646  }
647 
648  // If this bitmap doesn't have any data to free, skip
649  // the freeing it part of this.
650  if (bmp->data == 0) {
651 #ifdef BMPMAN_NDEBUG
652  if ( be->data_size != 0 ) {
653  bm_texture_ram -= be->data_size;
654  be->data_size = 0;
655  }
656 #endif
657  return;
658  }
659 
660  // Free up the data now!
661 #ifdef BMPMAN_NDEBUG
662  bm_texture_ram -= be->data_size;
663  be->data_size = 0;
664 #endif
665  vm_free((void *)bmp->data);
666  bmp->data = 0;
667 }
668 
669 int bm_get_cache_slot(int bitmap_id, int separate_ani_frames) {
670  int n = bitmap_id % MAX_BITMAPS;
671 
672  Assert(n >= 0);
673  Assert(bm_bitmaps[n].handle == bitmap_id); // INVALID BITMAP HANDLE
674 
675  bitmap_entry *be = &bm_bitmaps[n];
676 
677  if ((!separate_ani_frames) && ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF))) {
678  return be->info.ani.first_frame;
679  }
680 
681  return n;
682 
683 }
684 
685 void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) {
686  int bit_32 = 0;
687 
688  if ((gr_screen.bits_per_pixel == 32) && (Gr_current_red == &Gr_red)) {
689  bit_32 = 1;
690  }
691 
692  if (r != NULL) {
693  if (bit_32) {
694  *r = ubyte(((*((unsigned int*)pixel) & Gr_current_red->mask) >> Gr_current_red->shift)*Gr_current_red->scale);
695  } else {
696  *r = ubyte(((((unsigned short*)pixel)[0] & Gr_current_red->mask) >> Gr_current_red->shift)*Gr_current_red->scale);
697  }
698  }
699 
700  if (g != NULL) {
701  if (bit_32) {
702  *g = ubyte(((*((unsigned int*)pixel) & Gr_current_green->mask) >> Gr_current_green->shift)*Gr_current_green->scale);
703  } else {
704  *g = ubyte(((((unsigned short*)pixel)[0] & Gr_current_green->mask) >> Gr_current_green->shift)*Gr_current_green->scale);
705  }
706  }
707 
708  if (b != NULL) {
709  if (bit_32) {
710  *b = ubyte(((*((unsigned int*)pixel) & Gr_current_blue->mask) >> Gr_current_blue->shift)*Gr_current_blue->scale);
711  } else {
712  *b = ubyte(((((unsigned short*)pixel)[0] & Gr_current_blue->mask) >> Gr_current_blue->shift)*Gr_current_blue->scale);
713  }
714  }
715 
716  // get the alpha value
717  if (a != NULL) {
718  *a = 1;
719 
720  Assert(!bit_32);
721  if (!(((unsigned short*)pixel)[0] & 0x8000)) {
722  *a = 0;
723  }
724  }
725 }
726 
727 const char *bm_get_filename(int handle) {
728  int n;
729 
730  n = handle % MAX_BITMAPS;
731  Assert(bm_bitmaps[n].handle == handle); // INVALID BITMAP HANDLE
732  return bm_bitmaps[n].filename;
733 }
734 
735 void bm_get_filename(int bitmapnum, char *filename) {
736  if (!bm_is_valid(bitmapnum)) {
737  strcpy(filename, "");
738  return;
739  }
740 
741  int n = bitmapnum % MAX_BITMAPS;
742 
743  Assert(n >= 0);
744 
745  // return filename
746  strcpy(filename, bm_bitmaps[n].filename);
747 }
748 
749 void bm_get_frame_usage(int *ntotal, int *nnew) {
750 #ifdef BMPMAN_NDEBUG
751  int i;
752 
753  *ntotal = 0;
754  *nnew = 0;
755 
756  for (i = 0; i<MAX_BITMAPS; i++) {
757  if ((bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].used_this_frame)) {
758  if (!bm_bitmaps[i].used_last_frame) {
759  *nnew += (int)bm_bitmaps[i].mem_taken;
760  }
761  *ntotal += (int)bm_bitmaps[i].mem_taken;
762  }
763  bm_bitmaps[i].used_last_frame = bm_bitmaps[i].used_this_frame;
764  bm_bitmaps[i].used_this_frame = 0;
765  }
766 #endif
767 }
768 
769 int bm_get_info(int handle, int *w, int * h, ubyte * flags, int *nframes, int *fps) {
770  bitmap * bmp;
771 
772  if (!bm_inited) return -1;
773 
774  int bitmapnum = handle % MAX_BITMAPS;
775 
776 #ifndef NDEBUG
777  if (bm_bitmaps[bitmapnum].handle != handle) {
778  mprintf(("bm_get_info - %s: bm_bitmaps[%d].handle = %d, handle = %d\n", bm_bitmaps[bitmapnum].filename, bitmapnum, bm_bitmaps[bitmapnum].handle, handle));
779  }
780 #endif
781 
782  Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_info().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
783 
784  if ((bm_bitmaps[bitmapnum].type == BM_TYPE_NONE) || (bm_bitmaps[bitmapnum].handle != handle)) {
785  if (w) *w = 0;
786  if (h) *h = 0;
787  if (flags) *flags = 0;
788  if (nframes) *nframes = 0;
789  if (fps) *fps = 0;
790  return -1;
791  }
792 
793  bmp = &(bm_bitmaps[bitmapnum].bm);
794 
795  if (w) *w = bmp->w;
796  if (h) *h = bmp->h;
797  if (flags) *flags = bmp->flags;
798 
799  if ((bm_bitmaps[bitmapnum].type == BM_TYPE_ANI) || (bm_bitmaps[bitmapnum].type == BM_TYPE_EFF)) {
800  if (nframes) {
801  *nframes = bm_bitmaps[bitmapnum].info.ani.num_frames;
802  }
803  if (fps) {
804  *fps = bm_bitmaps[bitmapnum].info.ani.fps;
805  }
806 
807  return bm_bitmaps[bm_bitmaps[bitmapnum].info.ani.first_frame].handle;
808  } else {
809  if (nframes) {
810  *nframes = 1;
811  }
812  if (fps) {
813  *fps = 0;
814  }
815 
816  return handle;
817  }
818 }
819 
821  //bm_next_handle used to wrap around to 1 if it was over 30000. Now, believe it or not, but that is actually not uncommon;
822  //as bitmaps get allocated and released, bm_next_handle could get there far more often than you'd think.
823  //The check introduced below is intended to replace this behaviour with one that ensures we won't be seeing handle collisions
824  //for a very long time.
825 
826  bm_next_handle++;
827 
828  //Due to the way bm_next_handle is used to generate the /actual/ bitmap handles ( (bm_next_handle * MAX_BITMAPS) + free slot index in bm_bitmaps[]),
829  //this check is necessary to ensure we don't start giving out negative handles all of a sudden.
830  if ((bm_next_handle + 1) > INT_MAX / MAX_BITMAPS) {
831  bm_next_handle = 1;
832  mprintf(("BMPMAN: bitmap handles wrapped back to 1\n"));
833  }
834 
835  return bm_next_handle;
836 }
837 
839  int n = num % MAX_BITMAPS;
840 
841  Assert(n >= 0);
842  Assert(num == bm_bitmaps[n].handle);
843 
844  if (bm_bitmaps[n].num_mipmaps == 0)
845  return 1;
846 
847  return bm_bitmaps[n].num_mipmaps;
848 }
849 
850 void bm_get_palette(int handle, ubyte *pal, char *name) {
851  char *filename;
852  int w, h;
853 
854  int n = handle % MAX_BITMAPS;
855  Assert(bm_bitmaps[n].handle == handle); // INVALID BITMAP HANDLE
856 
857  filename = bm_bitmaps[n].filename;
858 
859  if (name) {
860  strcpy(name, filename);
861  }
862 
863  int pcx_error = pcx_read_header(filename, NULL, &w, &h, NULL, pal);
864  if (pcx_error != PCX_ERROR_NONE) {
865  // Error(LOCATION, "Couldn't open '%s'\n", filename );
866  }
867 }
868 
869 uint bm_get_signature(int handle) {
870  if (!bm_inited) bm_init();
871 
872  int bitmapnum = handle % MAX_BITMAPS;
873  Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_signature().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
874 
875  return bm_bitmaps[bitmapnum].signature;
876 }
877 
878 size_t bm_get_size(int handle) {
879  int n = handle % MAX_BITMAPS;
880 
881  Assert(n >= 0);
882  Assert(handle == bm_bitmaps[n].handle);
883 
884  return bm_bitmaps[n].mem_taken;
885 }
886 
888  if (bm_is_compressed(num))
889  return TCACHE_TYPE_COMPRESSED;
890 
891  return TCACHE_TYPE_NORMAL;
892 }
893 
894 BM_TYPE bm_get_type(int handle) {
895  if (!bm_inited) bm_init();
896 
897  int bitmapnum = handle % MAX_BITMAPS;
898  Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_type().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
899 
900  return bm_bitmaps[bitmapnum].type;
901 }
902 
903 bool bm_has_alpha_channel(int handle) {
904  int n = handle % MAX_BITMAPS;
905 
906  Assert(n >= 0);
907  Assert(handle == bm_bitmaps[n].handle);
908 
909  // assume that PCX never has a real alpha channel (it may be 32-bit, but without any alpha)
910  if (bm_bitmaps[n].type == BM_TYPE_PCX)
911  return 0;
912 
913  return (bm_bitmaps[n].bm.true_bpp == 32);
914 }
915 
916 void bm_init() {
917  int i;
918 
919  mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", sizeof(bm_bitmaps) / 1024));
920  mprintf(("Size of bitmap extra info = " SIZE_T_ARG " bytes\n", sizeof(bm_extra_info)));
921 
922  if (!bm_inited) {
923  bm_inited = 1;
924  atexit(bm_close);
925  }
926 
927  for (i = 0; i<MAX_BITMAPS; i++) {
928  bm_bitmaps[i].filename[0] = '\0';
929  bm_bitmaps[i].type = BM_TYPE_NONE;
930  bm_bitmaps[i].comp_type = BM_TYPE_NONE;
931  bm_bitmaps[i].dir_type = CF_TYPE_ANY;
932  bm_bitmaps[i].info.user.data = NULL;
933  bm_bitmaps[i].mem_taken = 0;
934  bm_bitmaps[i].bm.data = 0;
935  bm_bitmaps[i].bm.palette = NULL;
936  bm_bitmaps[i].info.ani.eff.type = BM_TYPE_NONE;
937  bm_bitmaps[i].info.ani.eff.filename[0] = '\0';
938 #ifdef BMPMAN_NDEBUG
939  bm_bitmaps[i].data_size = 0;
940  bm_bitmaps[i].used_count = 0;
941  bm_bitmaps[i].used_last_frame = 0;
942  bm_bitmaps[i].used_this_frame = 0;
943 #endif
944  bm_bitmaps[i].load_count = 0;
945 
946  gr_bm_init(i);
947 
948  bm_free_data(i); // clears flags, bbp, data, etc
949  }
950 }
951 
953  int n = num % MAX_BITMAPS;
955 
956  //duh
958  return 0;
959 
960  Assert(n >= 0);
961  Assert(num == bm_bitmaps[n].handle);
962 
963  type = bm_bitmaps[n].comp_type;
964 
965  switch (type) {
966  case BM_TYPE_NONE:
967  case BM_TYPE_DDS:
968  return 0;
969 
970  case BM_TYPE_DXT1:
971  return DDS_DXT1;
972 
973  case BM_TYPE_DXT3:
974  return DDS_DXT3;
975 
976  case BM_TYPE_DXT5:
977  return DDS_DXT5;
978 
980  return DDS_CUBEMAP_DXT1;
981 
983  return DDS_CUBEMAP_DXT3;
984 
986  return DDS_CUBEMAP_DXT5;
987 
988  default:
989  return 0;
990  }
991 }
992 
993 int bm_is_render_target(int bitmap_id) {
994  int n = bitmap_id % MAX_BITMAPS;
995 
996  Assert(n >= 0);
997  Assert(bitmap_id == bm_bitmaps[n].handle);
998 
999  if (!((bm_bitmaps[n].type == BM_TYPE_RENDER_TARGET_STATIC) || (bm_bitmaps[n].type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
1000  return 0;
1001  }
1002 
1003  return bm_bitmaps[n].type;
1004 }
1005 
1006 int bm_is_valid(int handle) {
1007  // Ensure that certain known false or out of range handles are quickly returned as invalid,
1008  // prior to utilising the handle in a way which leads to memory access outside bm_bitmaps[]
1009  if (!bm_inited) return 0;
1010  if (handle < 0) return 0;
1011 
1012  return (bm_bitmaps[handle % MAX_BITMAPS].handle == handle);
1013 }
1014 
1015 
1016 // Load an image and validate it while retrieving information for later use
1017 // Input: type = current BM_TYPE_*
1018 // n = location in bm_bitmaps[]
1019 // filename = name of the current file
1020 // img_cfp = already open CFILE handle, if available
1021 //
1022 // Output: w = bmp width
1023 // h = bmp height
1024 // bpp = bmp bits per pixel
1025 // c_type = output for an updated BM_TYPE_*
1026 // mm_lvl = number of mipmap levels for the image
1027 // size = size of the data contained in the image
1028 static int bm_load_info(BM_TYPE type, int n, const char *filename, CFILE *img_cfp, int *w, int *h, int *bpp, BM_TYPE *c_type, int *mm_lvl, int *size)
1029 {
1030  int dds_ct;
1031 
1032  if (type == BM_TYPE_DDS) {
1033  int dds_error = dds_read_header(filename, img_cfp, w, h, bpp, &dds_ct, mm_lvl, size);
1034 
1035  if (dds_error != DDS_ERROR_NONE) {
1036  mprintf(("DDS ERROR: Couldn't open '%s' -- %s\n", filename, dds_error_string(dds_error)));
1037  return -1;
1038  }
1039 
1040  switch (dds_ct) {
1041  case DDS_DXT1:
1042  *c_type = BM_TYPE_DXT1;
1043  break;
1044 
1045  case DDS_DXT3:
1046  *c_type = BM_TYPE_DXT3;
1047  break;
1048 
1049  case DDS_DXT5:
1050  *c_type = BM_TYPE_DXT5;
1051  break;
1052 
1053  case DDS_UNCOMPRESSED:
1054  *c_type = BM_TYPE_DDS;
1055  break;
1056 
1057  case DDS_CUBEMAP_DXT1:
1058  *c_type = BM_TYPE_CUBEMAP_DXT1;
1059  break;
1060 
1061  case DDS_CUBEMAP_DXT3:
1062  *c_type = BM_TYPE_CUBEMAP_DXT3;
1063  break;
1064 
1065  case DDS_CUBEMAP_DXT5:
1066  *c_type = BM_TYPE_CUBEMAP_DXT5;
1067  break;
1068 
1070  *c_type = BM_TYPE_CUBEMAP_DDS;
1071  break;
1072 
1073  default:
1074  Error(LOCATION, "Bad DDS file compression! Not using DXT1,3,5: %s", filename);
1075  return -1;
1076  }
1077  }
1078  // if its a tga file
1079  else if (type == BM_TYPE_TGA) {
1080  int tga_error = targa_read_header(filename, img_cfp, w, h, bpp, NULL);
1081  if (tga_error != TARGA_ERROR_NONE) {
1082  mprintf(("tga: Couldn't open '%s'\n", filename));
1083  return -1;
1084  }
1085  }
1086  // if its a png file
1087  else if (type == BM_TYPE_PNG) {
1088  int png_error = png_read_header(filename, img_cfp, w, h, bpp, NULL);
1089  if (png_error != PNG_ERROR_NONE) {
1090  mprintf(("png: Couldn't open '%s'\n", filename));
1091  return -1;
1092  }
1093  }
1094  // if its a jpg file
1095  else if (type == BM_TYPE_JPG) {
1096  int jpg_error = jpeg_read_header(filename, img_cfp, w, h, bpp, NULL);
1097  if (jpg_error != JPEG_ERROR_NONE) {
1098  mprintf(("jpg: Couldn't open '%s'\n", filename));
1099  return -1;
1100  }
1101  }
1102  // if its a pcx file
1103  else if (type == BM_TYPE_PCX) {
1104  int pcx_error = pcx_read_header(filename, img_cfp, w, h, bpp, NULL);
1105  if (pcx_error != PCX_ERROR_NONE) {
1106  mprintf(("pcx: Couldn't open '%s'\n", filename));
1107  return -1;
1108  }
1109  }
1110  else {
1111  Assertion(false, "Unknown file type specified! This is probably a coding error.");
1112 
1113  return -1;
1114  }
1115 
1116  return 0;
1117 }
1118 
1119 int bm_load(const char *real_filename) {
1120  int i, free_slot = -1;
1121  int w, h, bpp = 8;
1122  int rc = 0;
1123  int bm_size = 0, mm_lvl = 0;
1124  char filename[MAX_FILENAME_LEN];
1125  BM_TYPE type = BM_TYPE_NONE;
1126  BM_TYPE c_type = BM_TYPE_NONE;
1127  CFILE *img_cfp = NULL;
1128  int handle = -1;
1129 
1130  if (!bm_inited)
1131  bm_init();
1132 
1133  // if no file was passed then get out now
1134  if ((real_filename == NULL) || (strlen(real_filename) <= 0))
1135  return -1;
1136 
1137  // make sure no one passed an extension
1138  memset(filename, 0, MAX_FILENAME_LEN);
1139  strncpy(filename, real_filename, MAX_FILENAME_LEN - 1);
1140  char *p = strrchr(filename, '.');
1141  if (p) {
1142  mprintf(("Someone passed an extension to bm_load for file '%s'\n", real_filename));
1143  *p = 0;
1144  }
1145 
1146  // If we are standalone server keep replacing the 'right_bracket' (right side help bracket) as the filename
1147  // should keep the game happy while loading only single pcx file which the needs to be present in any case
1148  if (Is_standalone) {
1149  char standalone_filename[MAX_FILENAME_LEN] = "right_bracket";
1150  strcpy_s(filename, standalone_filename);
1151  }
1152 
1153  // safety catch for strcat...
1154  // MAX_FILENAME_LEN-5 == '.' plus 3 letter ext plus NULL terminator
1155  if (strlen(filename) > MAX_FILENAME_LEN - 5) {
1156  Warning(LOCATION, "Passed filename, '%s', is too long to support an extension!!\n\nMaximum length, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 5);
1157  return -1;
1158  }
1159 
1160  // Lets find out what type it is
1161  {
1162  // see if it's already loaded (checks for any type with filename)
1163  if (bm_load_sub_fast(filename, &handle))
1164  return handle;
1165 
1166  // if we are still here then we need to fall back to a file-based search
1167  int rval = bm_load_sub_slow(filename, BM_NUM_TYPES, bm_ext_list, &img_cfp);
1168 
1169  if (rval < 0)
1170  return -1;
1171 
1172  strcat_s(filename, bm_ext_list[rval]);
1173  type = bm_type_list[rval];
1174  }
1175 
1176  Assert(type != BM_TYPE_NONE);
1177 
1178  // Find an open slot
1179  for (i = 0; i < MAX_BITMAPS; i++) {
1180  if (bm_bitmaps[i].type == BM_TYPE_NONE) {
1181  free_slot = i;
1182  break;
1183  }
1184  }
1185 
1186  if (free_slot < 0) {
1187  Assertion(free_slot < 0, "Could not find free BMPMAN slot for bitmap: %s", real_filename);
1188  goto Done;
1189  }
1190 
1191  rc = bm_load_info(type, free_slot, filename, img_cfp, &w, &h, &bpp, &c_type, &mm_lvl, &bm_size);
1192 
1193  if (rc != 0)
1194  goto Done;
1195 
1196  if ((bm_size <= 0) && (w) && (h) && (bpp))
1197  bm_size = (w * h * (bpp >> 3));
1198 
1199 
1200  handle = bm_get_next_handle() * MAX_BITMAPS + free_slot;
1201 
1202  // ensure fields are cleared out from previous bitmap
1203  memset(&bm_bitmaps[free_slot], 0, sizeof(bitmap_entry));
1204 
1205  // Mark the slot as filled, because cf_read might load a new bitmap
1206  // into this slot.
1207  strncpy(bm_bitmaps[free_slot].filename, filename, MAX_FILENAME_LEN - 1);
1208  bm_bitmaps[free_slot].type = type;
1209  bm_bitmaps[free_slot].comp_type = c_type;
1210  bm_bitmaps[free_slot].signature = Bm_next_signature++;
1211  bm_bitmaps[free_slot].bm.w = (short)w;
1212  bm_bitmaps[free_slot].bm.rowsize = (short)w;
1213  bm_bitmaps[free_slot].bm.h = (short)h;
1214  bm_bitmaps[free_slot].bm.bpp = 0;
1215  bm_bitmaps[free_slot].bm.true_bpp = (ubyte)bpp;
1216  bm_bitmaps[free_slot].bm.flags = 0;
1217  bm_bitmaps[free_slot].bm.data = 0;
1218  bm_bitmaps[free_slot].bm.palette = NULL;
1219  bm_bitmaps[free_slot].num_mipmaps = mm_lvl;
1220  bm_bitmaps[free_slot].mem_taken = (size_t)bm_size;
1221  bm_bitmaps[free_slot].dir_type = CF_TYPE_ANY;
1222  bm_bitmaps[free_slot].palette_checksum = 0;
1223  bm_bitmaps[free_slot].handle = handle;
1224  bm_bitmaps[free_slot].last_used = -1;
1225 
1226  bm_bitmaps[free_slot].load_count++;
1227 
1228 Done:
1229  if (img_cfp != NULL)
1230  cfclose(img_cfp);
1231 
1232  return handle;
1233 }
1234 
1235 int bm_load(const SCP_string& filename) {
1236  return bm_load(filename.c_str());
1237 }
1238 
1239 bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type) {
1240  int frames = 0, fps = 30, keyframe = 0;
1241  char ext[8];
1242  BM_TYPE c_type = BM_TYPE_NONE;
1243  char file_text[1024];
1244  char file_text_raw[1024];
1245 
1246  memset(ext, 0, sizeof(ext));
1247  memset(file_text, 0, sizeof(file_text));
1248  memset(file_text_raw, 0, sizeof(file_text_raw));
1249 
1250  // pause anything that may happen to be parsing right now
1251  pause_parse();
1252 
1253  try
1254  {
1255  // now start parsing the EFF
1256  read_file_text(filename, dir_type, file_text, file_text_raw);
1257  reset_parse(file_text);
1258 
1259  required_string("$Type:");
1260  stuff_string(ext, F_NAME, sizeof(ext));
1261 
1262  required_string("$Frames:");
1263  stuff_int(&frames);
1264 
1265  if (optional_string("$FPS:"))
1266  stuff_int(&fps);
1267 
1268  if (optional_string("$Keyframe:"))
1269  stuff_int(&keyframe);
1270  }
1271  catch (const parse::ParseException& e)
1272  {
1273  mprintf(("BMPMAN: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
1274  unpause_parse();
1275  return false;
1276  }
1277 
1278  // done with EFF so unpause parsing so whatever can continue
1279  unpause_parse();
1280 
1281  if (!stricmp(NOX("dds"), ext)) {
1282  c_type = BM_TYPE_DDS;
1283  } else if (!stricmp(NOX("tga"), ext)) {
1284  c_type = BM_TYPE_TGA;
1285  } else if (!stricmp(NOX("png"), ext)) {
1286  c_type = BM_TYPE_PNG;
1287  } else if (!stricmp(NOX("jpg"), ext)) {
1288  c_type = BM_TYPE_JPG;
1289  } else if (!stricmp(NOX("pcx"), ext)) {
1290  c_type = BM_TYPE_PCX;
1291  } else {
1292  mprintf(("BMPMAN: Unknown file type in EFF parse!\n"));
1293  return false;
1294  }
1295 
1296  // did we do anything?
1297  if (c_type == BM_TYPE_NONE || frames == 0) {
1298  mprintf(("BMPMAN: EFF parse ERROR!\n"));
1299  return false;
1300  }
1301 
1302  if (type)
1303  *type = c_type;
1304 
1305  if (nframes)
1306  *nframes = frames;
1307 
1308  if (nfps)
1309  *nfps = fps;
1310 
1311  if (key)
1312  *key = keyframe;
1313 
1314  return true;
1315 }
1316 
1317 
1321 static int bm_load_image_data(const char *filename, int handle, int bitmapnum, ubyte bpp, ubyte flags, bool nodebug)
1322 {
1323  BM_TYPE c_type = BM_TYPE_NONE;
1324  ubyte true_bpp;
1325 
1326  bitmap_entry *be = &bm_bitmaps[bitmapnum];
1327  bitmap *bmp = &be->bm;
1328 
1330 
1331  if (bmp->true_bpp > bpp)
1332  true_bpp = bmp->true_bpp;
1333  else
1334  true_bpp = bpp;
1335 
1336  // don't do a bpp check here since it could be different in OGL - taylor
1337  if (bmp->data == 0) {
1338  Assert(be->ref_count == 1);
1339 
1340  if (be->type != BM_TYPE_USER && !nodebug) {
1341  if (bmp->data == 0)
1342  nprintf(("BmpMan", "Loading %s for the first time.\n", be->filename));
1343  }
1344 
1345  if (!Bm_paging) {
1346  if (be->type != BM_TYPE_USER && !nodebug)
1347  nprintf(("Paging", "Loading %s (%dx%dx%d)\n", be->filename, bmp->w, bmp->h, true_bpp));
1348  }
1349 
1350  // select proper format
1351  if (flags & BMP_AABITMAP)
1353  else if (flags & BMP_TEX_ANY)
1355  else
1357 
1358  // make sure we use the real graphic type for EFFs
1359  if (be->type == BM_TYPE_EFF) {
1360  c_type = be->info.ani.eff.type;
1361  }
1362  else {
1363  c_type = be->type;
1364  }
1365 
1366  switch (c_type)
1367  {
1368  case BM_TYPE_PCX:
1369  bm_lock_pcx(handle, bitmapnum, be, bmp, true_bpp, flags);
1370  break;
1371 
1372  case BM_TYPE_ANI:
1373  bm_lock_ani(handle, bitmapnum, be, bmp, true_bpp, flags);
1374  break;
1375 
1376  case BM_TYPE_TGA:
1377  bm_lock_tga(handle, bitmapnum, be, bmp, true_bpp, flags);
1378  break;
1379 
1380  case BM_TYPE_PNG:
1381  //libpng handles compression with zlib
1382  bm_lock_png(handle, bitmapnum, be, bmp, true_bpp, flags);
1383  break;
1384 
1385  case BM_TYPE_JPG:
1386  bm_lock_jpg(handle, bitmapnum, be, bmp, true_bpp, flags);
1387  break;
1388 
1389  case BM_TYPE_DDS:
1390  case BM_TYPE_DXT1:
1391  case BM_TYPE_DXT3:
1392  case BM_TYPE_DXT5:
1393  case BM_TYPE_CUBEMAP_DDS:
1394  case BM_TYPE_CUBEMAP_DXT1:
1395  case BM_TYPE_CUBEMAP_DXT3:
1396  case BM_TYPE_CUBEMAP_DXT5:
1397  bm_lock_dds(handle, bitmapnum, be, bmp, true_bpp, flags);
1398  break;
1399 
1400  case BM_TYPE_USER:
1401  bm_lock_user(handle, bitmapnum, be, bmp, true_bpp, flags);
1402  break;
1403 
1404  default:
1405  Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", c_type);
1406  return -1;
1407  }
1408 
1409  // always go back to screen format
1411 
1412  // make sure we actually did something
1413  if (!(bmp->data))
1414  return -1;
1415  }
1416 
1417  return 0;
1418 }
1419 
1420 int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type) {
1421  int i, n;
1422  anim the_anim;
1423  CFILE *img_cfp = NULL;
1424  char filename[MAX_FILENAME_LEN];
1425  int reduced = 0;
1426  int anim_fps = 0, anim_frames = 0, key = 0;
1427  int anim_width = 0, anim_height = 0;
1428  BM_TYPE type = BM_TYPE_NONE, eff_type = BM_TYPE_NONE, c_type = BM_TYPE_NONE;
1429  int bpp = 0, mm_lvl = 0, img_size = 0;
1430  char clean_name[MAX_FILENAME_LEN];
1431 
1432  if (!bm_inited)
1433  bm_init();
1434 
1435  // set defaults for frame count and fps before going any further
1436  if (nframes)
1437  *nframes = 0;
1438 
1439  if (fps)
1440  *fps = 0;
1441 
1442  if (keyframe)
1443  *keyframe = 0;
1444 
1445  memset(filename, 0, MAX_FILENAME_LEN);
1446  strncpy(filename, real_filename, MAX_FILENAME_LEN - 1);
1447  char *p = strchr(filename, '.');
1448  if (p) {
1449  mprintf(("Someone passed an extension to bm_load_animation for file '%s'\n", real_filename));
1450  *p = 0;
1451  }
1452 
1453  // If we are standalone server keep replacing the 'cursorweb' (mouse cursor) as the filename
1454  // should keep the game happy while loading only single ani file which the needs to be present in any case
1455  if (Is_standalone) {
1456  char standalone_filename[MAX_FILENAME_LEN] = "cursorweb";
1457  strcpy_s(filename, standalone_filename);
1458  }
1459 
1460  // safety catch for strcat...
1461  // MAX_FILENAME_LEN-5 == '.' plus 3 letter ext plus NULL terminator
1462  if (strlen(filename) > MAX_FILENAME_LEN - 5) {
1463  Warning(LOCATION, "Passed filename, '%s', is too long to support an extension!!\n\nMaximum length, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 5);
1464  return -1;
1465  }
1466 
1467  // used later if EFF type
1468  strcpy_s(clean_name, filename);
1469 
1470  // Lets find out what type it is
1471  {
1472  int handle = -1;
1473 
1474  // do a search for any previously loaded files (looks at filename only)
1475  if (bm_load_sub_fast(filename, &handle, dir_type, true)) {
1476  n = handle % MAX_BITMAPS;
1477  Assert(bm_bitmaps[n].handle == handle);
1478 
1479  if (nframes)
1480  *nframes = bm_bitmaps[n].info.ani.num_frames;
1481 
1482  if (fps)
1483  *fps = bm_bitmaps[n].info.ani.fps;
1484 
1485  if (keyframe)
1486  *keyframe = bm_bitmaps[n].info.ani.keyframe;
1487 
1488  return handle;
1489  }
1490 
1491  // if we are still here then we need to fall back to a file-based search
1492  int rval = bm_load_sub_slow(filename, BM_ANI_NUM_TYPES, bm_ani_ext_list, &img_cfp, dir_type);
1493 
1494  if (rval < 0)
1495  return -1;
1496 
1497  strcat_s(filename, bm_ani_ext_list[rval]);
1498  type = bm_ani_type_list[rval];
1499  }
1500 
1501  // If we found an animation then there is an extra 5 char size limit to adhere to. We don't do this check earlier since it's only needed if we found an anim
1502  // an ANI needs about 5 extra characters to have the "[###]" frame designator
1503  // an EFF needs 5 extra characters for each frame filename too, which just happens to be the same length as the frame designator needed otherwise
1504  // MAX_FILENAME_LEN-10 == 5 character frame designator plus '.' plus 3 letter ext plus NULL terminator
1505  // we only check for -5 here since the filename should already have the extension on it, and it must have passed the previous check
1506  if (strlen(filename) > MAX_FILENAME_LEN - 5) {
1507  Warning(LOCATION, "Passed filename, '%s', is too long to support an extension and frames!!\n\nMaximum length for an ANI/EFF, minus the extension, is %i characters.\n", filename, MAX_FILENAME_LEN - 10);
1508  return -1;
1509  }
1510 
1511  // it's an effect file, any readable image type with eff being txt
1512  if (type == BM_TYPE_EFF) {
1513  if (!bm_load_and_parse_eff(filename, dir_type, &anim_frames, &anim_fps, &key, &eff_type)) {
1514  mprintf(("BMPMAN: Error reading EFF\n"));
1515  return -1;
1516  } else {
1517  mprintf(("BMPMAN: Found EFF (%s) with %d frames at %d fps.\n", filename, anim_frames, anim_fps));
1518  }
1519  }
1520  // regular ani file
1521  else if (type == BM_TYPE_ANI) {
1522 #ifndef NDEBUG
1523  // for debug of ANI sizes
1524  strcpy_s(the_anim.name, real_filename);
1525 #endif
1526  anim_read_header(&the_anim, img_cfp);
1527 
1528  anim_frames = the_anim.total_frames;
1529  anim_fps = the_anim.fps;
1530  anim_width = the_anim.width;
1531  anim_height = the_anim.height;
1532  bpp = 8;
1533  img_size = (anim_width * anim_height * bpp);
1534  //we only care if there are 2 keyframes - first frame, other frame to jump to for ship/weapons
1535  //mainhall door anis hav every frame as keyframe, so we don't care
1536  //other anis only have the first frame
1537  if (the_anim.num_keys == 2) {
1538  the_anim.keys = (key_frame*)vm_malloc(sizeof(key_frame) * the_anim.num_keys);
1539  Assert(the_anim.keys != NULL);
1540 
1541  for (i = 0; i<the_anim.num_keys; i++) {
1542  the_anim.keys[i].frame_num = 0;
1543  cfread(&the_anim.keys[i].frame_num, 2, 1, img_cfp);
1544  cfread(&the_anim.keys[i].offset, 4, 1, img_cfp);
1545  the_anim.keys[i].frame_num = INTEL_INT(the_anim.keys[i].frame_num); //-V570
1546  the_anim.keys[i].offset = INTEL_INT(the_anim.keys[i].offset); //-V570
1547  }
1548  //some retail anis have their keyframes reversed
1549  key = MAX(the_anim.keys[0].frame_num, the_anim.keys[1].frame_num);
1550 
1551  vm_free(the_anim.keys);
1552  the_anim.keys = nullptr;
1553  }
1554  } else {
1555  return -1;
1556  }
1557 
1558  if ((can_drop_frames) && (type != BM_TYPE_EFF)) {
1559  if (Bm_low_mem == 1) {
1560  reduced = 1;
1561  anim_frames = (anim_frames + 1) / 2;
1562  anim_fps = (anim_fps / 2);
1563  } else if (Bm_low_mem == 2) {
1564  anim_frames = 1;
1565  }
1566  }
1567 
1568 
1569  n = find_block_of(anim_frames);
1570 
1571  if (n < 0) {
1572  if (img_cfp != NULL)
1573  cfclose(img_cfp);
1574 
1575  return -1;
1576  }
1577 
1578  int first_handle = bm_get_next_handle();
1579 
1580  for (i = 0; i < anim_frames; i++) {
1581  memset(&bm_bitmaps[n + i], 0, sizeof(bitmap_entry));
1582 
1583  if (type == BM_TYPE_EFF) {
1584  bm_bitmaps[n + i].info.ani.eff.type = eff_type;
1585  sprintf(bm_bitmaps[n + i].info.ani.eff.filename, "%s_%.4d", clean_name, i);
1586 
1587  // bm_load_info() returns non-0 on failure
1588  if (bm_load_info(eff_type, n + i, bm_bitmaps[n + i].info.ani.eff.filename, NULL, &anim_width, &anim_height, &bpp, &c_type, &mm_lvl, &img_size)) {
1589  // if we didn't get anything then bail out now
1590  if (i == 0) {
1591  Warning(LOCATION, "EFF: No frame images were found. EFF, %s, is invalid.\n", filename);
1592 
1593  if (img_cfp != NULL)
1594  cfclose(img_cfp);
1595 
1596  return -1;
1597  }
1598 
1599  Warning(LOCATION, "EFF: Unable to load all frames for '%s', stopping at #%d\n", filename, i);
1600 
1601  // reset total frames to current
1602  anim_frames = i;
1603 
1604  // update all previous frames with the new count
1605  for (int j = 0; j<anim_frames; j++)
1606  bm_bitmaps[n + j].info.ani.num_frames = anim_frames;
1607 
1608  break;
1609  }
1610 
1611  if ((img_size <= 0) && (anim_width) && (anim_height) && (bpp)) {
1612  img_size = (anim_width * anim_height * (bpp >> 3));
1613  }
1614  }
1615 
1616  bm_bitmaps[n + i].info.ani.first_frame = n;
1617  bm_bitmaps[n + i].info.ani.num_frames = anim_frames;
1618  bm_bitmaps[n + i].info.ani.fps = (ubyte)anim_fps;
1619  bm_bitmaps[n + i].info.ani.keyframe = key;
1620  bm_bitmaps[n + i].bm.w = (short)anim_width;
1621  bm_bitmaps[n + i].bm.rowsize = (short)anim_width;
1622  bm_bitmaps[n + i].bm.h = (short)anim_height;
1623  if (reduced) {
1624  bm_bitmaps[n + i].bm.w /= 2;
1625  bm_bitmaps[n + i].bm.rowsize /= 2;
1626  bm_bitmaps[n + i].bm.h /= 2;
1627  }
1628  bm_bitmaps[n + i].bm.flags = 0;
1629  bm_bitmaps[n + i].bm.bpp = 0;
1630  bm_bitmaps[n + i].bm.true_bpp = (ubyte)bpp;
1631  bm_bitmaps[n + i].bm.data = 0;
1632  bm_bitmaps[n + i].bm.palette = NULL;
1633  bm_bitmaps[n + i].type = type;
1634  bm_bitmaps[n + i].comp_type = c_type;
1635  bm_bitmaps[n + i].palette_checksum = 0;
1636  bm_bitmaps[n + i].signature = Bm_next_signature++;
1637  bm_bitmaps[n + i].handle = first_handle*MAX_BITMAPS + n + i;
1638  bm_bitmaps[n + i].last_used = -1;
1639  bm_bitmaps[n + i].num_mipmaps = mm_lvl;
1640  bm_bitmaps[n + i].mem_taken = (size_t)img_size;
1641  bm_bitmaps[n + i].dir_type = dir_type;
1642 
1643  bm_bitmaps[n + i].load_count++;
1644 
1645  if (i == 0) {
1646  sprintf(bm_bitmaps[n + i].filename, "%s", filename);
1647  } else {
1648  sprintf(bm_bitmaps[n + i].filename, "%s[%d]", filename, i);
1649  }
1650 
1651  }
1652 
1653  if (nframes)
1654  *nframes = anim_frames;
1655 
1656  if (fps)
1657  *fps = anim_fps;
1658 
1659  if (img_cfp != NULL)
1660  cfclose(img_cfp);
1661 
1662  if (keyframe)
1663  *keyframe = key;
1664 
1665  return bm_bitmaps[n].handle;
1666 }
1667 
1668 int bm_load_duplicate(const char *filename) {
1669  int ret;
1670 
1671  // ignore duplicates
1672  Bm_ignore_duplicates = 1;
1673 
1674  // load
1675  ret = bm_load(filename);
1676 
1677  // back to normal
1678  Bm_ignore_duplicates = 0;
1679 
1680  return ret;
1681 }
1682 
1683 int bm_load_either(const char *filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type) {
1684  if (nframes != NULL)
1685  *nframes = 0;
1686  if (fps != NULL)
1687  *fps = 0;
1688  int tidx = bm_load_animation(filename, nframes, fps, keyframe, can_drop_frames, dir_type);
1689  if (tidx == -1) {
1690  tidx = bm_load(filename);
1691  if (tidx != -1 && nframes != NULL)
1692  *nframes = 1;
1693  }
1694 
1695  return tidx;
1696 }
1697 
1698 int bm_load_sub_fast(const char *real_filename, int *handle, int dir_type, bool animated_type) {
1699  if (Bm_ignore_duplicates)
1700  return 0;
1701 
1702  int i;
1703 
1704  for (i = 0; i < MAX_BITMAPS; i++) {
1705  if (bm_bitmaps[i].type == BM_TYPE_NONE)
1706  continue;
1707 
1708  if (bm_bitmaps[i].dir_type != dir_type)
1709  continue;
1710 
1711  bool animated = ((bm_bitmaps[i].type == BM_TYPE_EFF) || (bm_bitmaps[i].type == BM_TYPE_ANI));
1712 
1713  if (animated_type && !animated)
1714  continue;
1715  else if (!animated_type && animated)
1716  continue;
1717 
1718  if (!strextcmp(real_filename, bm_bitmaps[i].filename)) {
1719  nprintf(("BmpFastLoad", "Found bitmap %s -- number %d\n", bm_bitmaps[i].filename, i));
1720  bm_bitmaps[i].load_count++;
1721  *handle = bm_bitmaps[i].handle;
1722  return 1;
1723  }
1724  }
1725 
1726  // not found to be loaded already
1727  return 0;
1728 }
1729 
1730 int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **ext_list, CFILE **img_cfp, int dir_type) {
1731  char full_path[MAX_PATH];
1732  int size = 0, offset = 0;
1733  int rval = -1;
1734 
1735  rval = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, sizeof(full_path) - 1, full_path, &size, &offset, 0);
1736 
1737  // could not be found, or is invalid for some reason
1738  if ((rval < 0) || (rval >= num_ext))
1739  return -1;
1740 
1741  CFILE *test = cfopen_special(full_path, "rb", size, offset, dir_type);
1742 
1743  if (test != NULL) {
1744  if (img_cfp != NULL)
1745  *img_cfp = test;
1746 
1747  return rval;
1748  }
1749 
1750  // umm, that's not good...
1751  return -1;
1752 }
1753 
1754 bitmap * bm_lock(int handle, ubyte bpp, ubyte flags, bool nodebug) {
1755  bitmap *bmp;
1756  bitmap_entry *be;
1757 
1758  if (!bm_inited) bm_init();
1759 
1760  int bitmapnum = handle % MAX_BITMAPS;
1761 
1762  Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid handle %d passed to bm_lock. This might be due to an animation elsewhere in the code being too short.\n", handle); // INVALID BITMAP HANDLE
1763 
1764  // to fix a couple of OGL bpp passes, force 8bit on AABITMAP - taylor
1765  if (flags & BMP_AABITMAP)
1766  bpp = 8;
1767 
1768  // if we're on a standalone server, aways for it to lock to 8 bits
1769  if (Is_standalone) {
1770  bpp = 8;
1771  flags = 0;
1772  }
1773  // otherwise do it as normal
1774  else {
1775  if (flags & BMP_AABITMAP) {
1776  Assert(bpp == 8);
1777  } else if ((flags & BMP_TEX_NONCOMP) && (!(flags & BMP_TEX_COMP))) {
1778  Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
1779  } else if ((flags & BMP_TEX_DXT1) || (flags & BMP_TEX_DXT3) || (flags & BMP_TEX_DXT5)) {
1780  Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
1781  } else if (flags & BMP_TEX_CUBEMAP) {
1782  Assert((bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DDS) ||
1783  (bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DXT1) ||
1784  (bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DXT3) ||
1785  (bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DXT5));
1786  Assert(bpp >= 16);
1787  } else {
1788  Assert(0); //?
1789  }
1790  }
1791 
1792  be = &bm_bitmaps[bitmapnum];
1793  bmp = &be->bm;
1794 
1795  // If you hit this assert, chances are that someone freed the
1796  // wrong bitmap and now someone is trying to use that bitmap.
1797  // See John.
1798  Assert(be->type != BM_TYPE_NONE);
1799 
1800  // Increment ref count for bitmap since lock was made on it.
1801  Assert(be->ref_count >= 0);
1802  be->ref_count++; // Lock it before we page in data; this prevents a callback from freeing this
1803  // as it gets read in
1804 
1805  // Mark this bitmap as used this frame
1806 #ifdef BMPMAN_NDEBUG
1807  if (be->used_this_frame < 255) {
1808  be->used_this_frame++;
1809  }
1810 #endif
1811 
1812  // read the file data
1813  if (bm_load_image_data(be->filename, handle, bitmapnum, bpp, flags, nodebug) == -1) {
1814  // oops, this isn't good - reset and return NULL
1815  bm_unlock( handle );
1816  bm_unload( handle );
1817 
1818  return NULL;
1819  }
1820 
1821  if (!gr_bm_data(bitmapnum, bmp)) {
1822  // graphics subsystem failed, reset and return NULL
1823  bm_unlock( handle );
1824  bm_unload( handle );
1825 
1826  return NULL;
1827  }
1828 
1829  MONITOR_INC(NumBitmapPage, 1);
1830  MONITOR_INC(SizeBitmapPage, bmp->w*bmp->h);
1831 
1832  if ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF)) {
1833  int i, first = bm_bitmaps[bitmapnum].info.ani.first_frame;
1834 
1835  for (i = 0; i< bm_bitmaps[first].info.ani.num_frames; i++) {
1836  // Mark all the bitmaps in this bitmap or animation as recently used
1837  bm_bitmaps[first + i].last_used = timer_get_milliseconds();
1838 
1839 #ifdef BMPMAN_NDEBUG
1840  // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
1841  bm_bitmaps[first + i].used_count++;
1842 #endif
1843 
1844  bm_bitmaps[first + i].used_flags = flags;
1845  }
1846  } else {
1847  // Mark all the bitmaps in this bitmap or animation as recently used
1849 
1850 #ifdef BMPMAN_NDEBUG
1851  // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
1852  be->used_count++;
1853 #endif
1854  be->used_flags = flags;
1855  }
1856 
1857  return bmp;
1858 }
1859 
1860 void bm_lock_ani(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
1861  anim *the_anim;
1862  anim_instance *the_anim_instance;
1863  bitmap *bm;
1864  ubyte *frame_data;
1865  int size, i;
1866  int first_frame, nframes;
1867 
1868  first_frame = be->info.ani.first_frame;
1869  nframes = bm_bitmaps[first_frame].info.ani.num_frames;
1870 
1871  if ((the_anim = anim_load(bm_bitmaps[first_frame].filename, bm_bitmaps[first_frame].dir_type)) == NULL) {
1872  nprintf(("BMPMAN", "Error opening %s in bm_lock\n", be->filename));
1873  return;
1874  }
1875 
1876  if ((the_anim_instance = init_anim_instance(the_anim, bpp)) == NULL) {
1877  nprintf(("BMPMAN", "Error opening %s in bm_lock\n", be->filename));
1878  anim_free(the_anim);
1879  return;
1880  }
1881 
1882  int can_drop_frames = 0;
1883 
1884  if (the_anim->total_frames != bm_bitmaps[first_frame].info.ani.num_frames) {
1885  can_drop_frames = 1;
1886  }
1887 
1888  bm = &bm_bitmaps[first_frame].bm;
1889  size = bm->w * bm->h * (bpp >> 3);
1890  be->mem_taken = (size_t)size;
1891 
1892  Assert(size > 0);
1893 
1894  for (i = 0; i<nframes; i++) {
1895  be = &bm_bitmaps[first_frame + i];
1896  bm = &bm_bitmaps[first_frame + i].bm;
1897 
1898  // Unload any existing data
1899  bm_free_data(first_frame + i);
1900 
1901  bm->flags = 0;
1902 
1903  // briefing editor in Fred2 uses aabitmaps (ani's) - force to 8 bit
1904  bm->bpp = Is_standalone ? (ubyte)8 : bpp;
1905 
1906  bm->data = (ptr_u)bm_malloc(first_frame + i, size);
1907 
1908  frame_data = anim_get_next_raw_buffer(the_anim_instance, 0, flags & BMP_AABITMAP ? 1 : 0, bm->bpp);
1909 
1910  ubyte *dptr, *sptr;
1911 
1912  sptr = frame_data;
1913  dptr = (ubyte *)bm->data;
1914 
1915  if ((bm->w != the_anim->width) || (bm->h != the_anim->height)) {
1916  // Scale it down
1917  // 8 bit
1918  if (bpp == 8) {
1919  int w, h;
1920  fix u, utmp, v, du, dv;
1921 
1922  u = v = 0;
1923 
1924  du = (the_anim->width*F1_0) / bm->w;
1925  dv = (the_anim->height*F1_0) / bm->h;
1926 
1927  for (h = 0; h < bm->h; h++) {
1928  ubyte *drow = &dptr[bm->w * h];
1929  ubyte *srow = &sptr[f2i(v)*the_anim->width];
1930 
1931  utmp = u;
1932 
1933  for (w = 0; w < bm->w; w++) {
1934  *drow++ = srow[f2i(utmp)];
1935  utmp += du;
1936  }
1937  v += dv;
1938  }
1939  }
1940  // 16 bpp
1941  else {
1942  int w, h;
1943  fix u, utmp, v, du, dv;
1944 
1945  u = v = 0;
1946 
1947  du = (the_anim->width*F1_0) / bm->w;
1948  dv = (the_anim->height*F1_0) / bm->h;
1949 
1950  for (h = 0; h < bm->h; h++) {
1951  unsigned short *drow = &((unsigned short*)dptr)[bm->w * h];
1952  unsigned short *srow = &((unsigned short*)sptr)[f2i(v)*the_anim->width];
1953 
1954  utmp = u;
1955 
1956  for (w = 0; w < bm->w; w++) {
1957  *drow++ = srow[f2i(utmp)];
1958  utmp += du;
1959  }
1960  v += dv;
1961  }
1962  }
1963  } else {
1964  // 1-to-1 mapping
1965  memcpy(dptr, sptr, size);
1966  }
1967 
1968  bm_convert_format(bm, flags);
1969 
1970  // Skip a frame
1971  if ((i < nframes - 1) && can_drop_frames) {
1972  frame_data = anim_get_next_raw_buffer(the_anim_instance, 0, flags & BMP_AABITMAP ? 1 : 0, bm->bpp);
1973  }
1974  }
1975 
1976  free_anim_instance(the_anim_instance);
1977  anim_free(the_anim);
1978 }
1979 
1980 void bm_lock_dds(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
1981  ubyte *data = NULL;
1982  int error;
1983  ubyte dds_bpp = 0;
1984  char filename[MAX_FILENAME_LEN];
1985 
1986  // free any existing data
1987  bm_free_data(bitmapnum);
1988 
1989  Assert(be->mem_taken > 0);
1990  Assert(&be->bm == bmp);
1991 
1992  data = (ubyte*)bm_malloc(bitmapnum, be->mem_taken);
1993 
1994  if (data == NULL)
1995  return;
1996 
1997  memset(data, 0, be->mem_taken);
1998 
1999  // make sure we are using the correct filename in the case of an EFF.
2000  // this will populate filename[] whether it's EFF or not
2002 
2003  error = dds_read_bitmap(filename, data, &dds_bpp, be->dir_type);
2004 
2005 #if BYTE_ORDER == BIG_ENDIAN
2006  // same as with TGA, we need to byte swap 16 & 32-bit, uncompressed, DDS images
2007  if ((be->comp_type == BM_TYPE_DDS) || (be->comp_type == BM_TYPE_CUBEMAP_DDS)) {
2008  size_t i = 0;
2009 
2010  if (dds_bpp == 32) {
2011  unsigned int *swap_tmp;
2012 
2013  for (i = 0; i < be->mem_taken; i += 4) {
2014  swap_tmp = (unsigned int *)(data + i);
2015  *swap_tmp = INTEL_INT(*swap_tmp);
2016  }
2017  } else if (dds_bpp == 16) {
2018  unsigned short *swap_tmp;
2019 
2020  for (i = 0; i < be->mem_taken; i += 2) {
2021  swap_tmp = (unsigned short *)(data + i);
2022  *swap_tmp = INTEL_SHORT(*swap_tmp);
2023  }
2024  }
2025  }
2026 #endif
2027 
2028  bmp->bpp = dds_bpp;
2029  bmp->data = (ptr_u)data;
2030  bmp->flags = 0;
2031 
2032  if (error != DDS_ERROR_NONE) {
2033  bm_free_data(bitmapnum);
2034  return;
2035  }
2036 
2037 #ifdef BMPMAN_NDEBUG
2038  Assert(be->data_size > 0);
2039 #endif
2040 }
2041 
2042 void bm_lock_jpg(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
2043  ubyte *data = NULL;
2044  int d_size = 0;
2045  int jpg_error = JPEG_ERROR_INVALID;
2046  char filename[MAX_FILENAME_LEN];
2047 
2048  // Unload any existing data
2049  bm_free_data(bitmapnum);
2050 
2051  d_size = (bpp >> 3);
2052 
2053  // allocate bitmap data
2054  Assert(be->mem_taken > 0);
2055  data = (ubyte*)bm_malloc(bitmapnum, be->mem_taken);
2056 
2057  if (data == NULL)
2058  return;
2059 
2060  memset(data, 0, be->mem_taken);
2061 
2062  bmp->bpp = bpp;
2063  bmp->data = (ptr_u)data;
2064  bmp->palette = NULL;
2065 
2066  Assert(&be->bm == bmp);
2067 
2068  // make sure we are using the correct filename in the case of an EFF.
2069  // this will populate filename[] whether it's EFF or not
2071 
2072  jpg_error = jpeg_read_bitmap(filename, data, NULL, d_size, be->dir_type);
2073 
2074  if (jpg_error != JPEG_ERROR_NONE) {
2075  bm_free_data(bitmapnum);
2076  return;
2077  }
2078 
2079 #ifdef BMPMAN_NDEBUG
2080  Assert(be->data_size > 0);
2081 #endif
2082 }
2083 
2084 void bm_lock_pcx(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
2085  ubyte *data;
2086  int pcx_error;
2087  char filename[MAX_FILENAME_LEN];
2088 
2089  // Unload any existing data
2090  bm_free_data(bitmapnum);
2091 
2092  be->mem_taken = (bmp->w * bmp->h * (bpp >> 3));
2093  data = (ubyte *)bm_malloc(bitmapnum, be->mem_taken);
2094  bmp->bpp = bpp;
2095  bmp->data = (ptr_u)data;
2096  bmp->palette = (bpp == 8) ? gr_palette : NULL;
2097  memset(data, 0, be->mem_taken);
2098 
2099  Assert(&be->bm == bmp);
2100 #ifdef BMPMAN_NDEBUG
2101  Assert(be->data_size > 0);
2102 #endif
2103 
2104  // some sanity checks on flags
2105  Assert(!((flags & BMP_AABITMAP) && (flags & BMP_TEX_ANY))); // no aabitmap textures
2106 
2107  // make sure we are using the correct filename in the case of an EFF.
2108  // this will populate filename[] whether it's EFF or not
2110 
2111  pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), 0, be->dir_type);
2112 
2113  if (pcx_error != PCX_ERROR_NONE) {
2114  mprintf(("Couldn't load PCX!!! (%s)\n", filename));
2115  return;
2116  }
2117 
2118 #ifdef BMPMAN_NDEBUG
2119  Assert(be->data_size > 0);
2120 #endif
2121 
2122  bmp->flags = 0;
2123 
2124  bm_convert_format(bmp, flags);
2125 }
2126 
2127 void bm_lock_png(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
2128  ubyte *data = NULL;
2129  //assume 32 bit - libpng should expand everything
2130  int d_size;
2131  int png_error = PNG_ERROR_INVALID;
2132  char filename[MAX_FILENAME_LEN];
2133 
2134  // Unload any existing data
2135  bm_free_data(bitmapnum);
2136 
2137  // allocate bitmap data
2138  Assert(bmp->w * bmp->h > 0);
2139 
2140  //if it's not 32-bit, we expand when we read it
2141  bmp->bpp = 32;
2142  d_size = bmp->bpp >> 3;
2143  //we waste memory if it turns out to be 24-bit, but the way this whole thing works is dodgy anyway
2144  data = (ubyte*)bm_malloc(bitmapnum, bmp->w * bmp->h * d_size);
2145  if (data == NULL)
2146  return;
2147  memset(data, 0, bmp->w * bmp->h * d_size);
2148  bmp->data = (ptr_u)data;
2149  bmp->palette = NULL;
2150 
2151  Assert(&be->bm == bmp);
2152 
2153  // make sure we are using the correct filename in the case of an EFF.
2154  // this will populate filename[] whether it's EFF or not
2156 
2157  //bmp->bpp gets set correctly in here after reading into memory
2158  png_error = png_read_bitmap(filename, data, &bmp->bpp, d_size, be->dir_type);
2159 
2160  if (png_error != PNG_ERROR_NONE) {
2161  bm_free_data(bitmapnum);
2162  return;
2163  }
2164 
2165 #ifdef BMPMAN_NDEBUG
2166  Assert(be->data_size > 0);
2167 #endif
2168 }
2169 
2170 void bm_lock_tga(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
2171  ubyte *data = NULL;
2172  int d_size, byte_size;
2173  char filename[MAX_FILENAME_LEN];
2174 
2175  // Unload any existing data
2176  bm_free_data(bitmapnum);
2177 
2178  if (Is_standalone) {
2179  Assert(bpp == 8);
2180  } else {
2181  Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
2182  }
2183 
2184  // allocate bitmap data
2185  byte_size = (bpp >> 3);
2186 
2187  Assert(byte_size);
2188  Assert(be->mem_taken > 0);
2189 
2190  data = (ubyte*)bm_malloc(bitmapnum, be->mem_taken);
2191 
2192  if (data) {
2193  memset(data, 0, be->mem_taken);
2194  d_size = byte_size;
2195  } else {
2196  return;
2197  }
2198 
2199  bmp->bpp = bpp;
2200  bmp->data = (ptr_u)data;
2201  bmp->palette = NULL;
2202 
2203  Assert(&be->bm == bmp);
2204 #ifdef BMPMAN_NDEBUG
2205  Assert(be->data_size > 0);
2206 #endif
2207 
2208  int tga_error;
2209 
2210  // make sure we are using the correct filename in the case of an EFF.
2211  // this will populate filename[] whether it's EFF or not
2213 
2214  tga_error = targa_read_bitmap(filename, data, NULL, d_size, be->dir_type);
2215 
2216  if (tga_error != TARGA_ERROR_NONE) {
2217  bm_free_data(bitmapnum);
2218  return;
2219  }
2220 
2221  bmp->flags = 0;
2222 
2223  bm_convert_format(bmp, flags);
2224 }
2225 
2226 void bm_lock_user(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
2227  // Unload any existing data
2228  bm_free_data(bitmapnum);
2229 
2230  if ((bpp != be->info.user.bpp) && !(flags & BMP_AABITMAP))
2231  bpp = be->info.user.bpp;
2232 
2233  switch (bpp) {
2234  case 32: // user 32-bit bitmap
2235  bmp->bpp = bpp;
2236  bmp->flags = be->info.user.flags;
2237  bmp->data = (ptr_u)be->info.user.data;
2238  break;
2239 
2240  case 24: // user 24-bit bitmap
2241  bmp->bpp = bpp;
2242  bmp->flags = be->info.user.flags;
2243  bmp->data = (ptr_u)be->info.user.data;
2244  break;
2245 
2246  case 16: // user 16 bit bitmap
2247  bmp->bpp = bpp;
2248  bmp->flags = be->info.user.flags;
2249  bmp->data = (ptr_u)be->info.user.data;
2250  break;
2251 
2252  case 8: // Going from 8 bpp to something (probably only for aabitmaps)
2253  Assert(flags & BMP_AABITMAP);
2254  bmp->bpp = bpp;
2255  bmp->flags = be->info.user.flags;
2256  bmp->data = (ptr_u)be->info.user.data;
2257  break;
2258 
2259  default:
2260  Error(LOCATION, "Unhandled user bitmap conversion from %d to %d bpp", be->info.user.bpp, bmp->bpp);
2261  break;
2262  }
2263 
2264  bm_convert_format(bmp, flags);
2265 }
2266 
2267 int bm_make_render_target(int width, int height, int flags) {
2268  int i, n;
2269  int mm_lvl = 0;
2270  // final w and h may be different from passed width and height
2271  int w = width, h = height;
2272  ubyte bpp = 32;
2273  int size = 0;
2274 
2275  if (!bm_inited)
2276  bm_init();
2277 
2278  // Find an open slot (starting from the end)
2279  for (n = -1, i = MAX_BITMAPS - 1; i >= 0; i--) {
2280  if (bm_bitmaps[i].type == BM_TYPE_NONE) {
2281  n = i;
2282  break;
2283  }
2284  }
2285 
2286  // Out of bitmap slots
2287  if (n == -1)
2288  return -1;
2289 
2290  if (!gr_bm_make_render_target(n, &w, &h, &bpp, &mm_lvl, flags))
2291  return -1;
2292 
2293  Assert(mm_lvl > 0);
2294 
2295  if (flags & BMP_FLAG_RENDER_TARGET_STATIC) {
2296  // data size
2297  size = (w * h * (bpp >> 3));
2298 
2299  if (mm_lvl > 1) {
2300  // include size of all mipmap levels (there should be a full chain)
2301  size += (size / 3) - 1;
2302  }
2303 
2304  // make sure to count all faces if a cubemap
2305  if (flags & BMP_FLAG_CUBEMAP) {
2306  size *= 6;
2307  }
2308  }
2309 
2310  // ensure fields are cleared out from previous bitmap
2311  memset(&bm_bitmaps[n], 0, sizeof(bitmap_entry));
2312 
2314  bm_bitmaps[n].signature = Bm_next_signature++;
2315  sprintf(bm_bitmaps[n].filename, "RT_%dx%d+%d", w, h, bpp);
2316  bm_bitmaps[n].bm.w = (short)w;
2317  bm_bitmaps[n].bm.h = (short)h;
2318  bm_bitmaps[n].bm.rowsize = (short)w;
2319  bm_bitmaps[n].bm.bpp = (ubyte)bpp;
2320  bm_bitmaps[n].bm.true_bpp = (ubyte)bpp;
2321  bm_bitmaps[n].bm.flags = (ubyte)flags;
2322  bm_bitmaps[n].bm.data = 0;
2323  bm_bitmaps[n].bm.palette = NULL;
2324  bm_bitmaps[n].num_mipmaps = mm_lvl;
2325  bm_bitmaps[n].mem_taken = (size_t)size;
2326  bm_bitmaps[n].dir_type = CF_TYPE_ANY;
2327 
2328  bm_bitmaps[n].palette_checksum = 0;
2329  bm_bitmaps[n].handle = bm_get_next_handle() * MAX_BITMAPS + n;
2330  bm_bitmaps[n].last_used = -1;
2331 
2332  if (bm_bitmaps[n].mem_taken) {
2333  bm_bitmaps[n].bm.data = (ptr_u)bm_malloc(n, bm_bitmaps[n].mem_taken);
2334  }
2335 
2336  return bm_bitmaps[n].handle;
2337 }
2338 
2339 void *bm_malloc(int n, int size) {
2340  Assert((n >= 0) && (n < MAX_BITMAPS));
2341 
2342  if (size <= 0)
2343  return NULL;
2344 
2345 #ifdef BMPMAN_NDEBUG
2346  Assert(bm_bitmaps[n].data_size == 0);
2347  bm_bitmaps[n].data_size += size;
2348  bm_texture_ram += size;
2349 #endif
2350 
2351  return vm_malloc(size);
2352 }
2353 
2354 void bm_page_in_aabitmap(int bitmapnum, int nframes) {
2355  int i;
2356  int n = bitmapnum % MAX_BITMAPS;
2357 
2358  if (n == -1)
2359  return;
2360 
2361  Assert(bm_bitmaps[n].handle == bitmapnum);
2362 
2363  for (i = 0; i<nframes; i++) {
2364  bm_bitmaps[n + i].preloaded = 2;
2365 
2366  bm_bitmaps[n + i].preload_count++;
2367 
2368  bm_bitmaps[n + i].used_flags = BMP_AABITMAP;
2369  }
2370 }
2371 
2373  int i;
2374 
2375  Bm_paging = 1;
2376 
2377  // Mark all as inited
2378  for (i = 0; i < MAX_BITMAPS; i++) {
2379  if (!Cmdline_cache_bitmaps && (bm_bitmaps[i].type != BM_TYPE_NONE)) {
2380  bm_unload_fast(bm_bitmaps[i].handle);
2381  }
2382  bm_bitmaps[i].preloaded = 0;
2383  bm_bitmaps[i].preload_count = 0;
2384 #ifdef BMPMAN_NDEBUG
2385  bm_bitmaps[i].used_count = 0;
2386 #endif
2387  bm_bitmaps[i].used_flags = 0;
2388  }
2389 
2391 }
2392 
2394  int i;
2395 
2396 #ifndef NDEBUG
2397  char busy_text[60];
2398 #endif
2399 
2400  nprintf(("BmpInfo", "BMPMAN: Loading all used bitmaps.\n"));
2401 
2402  // Load all the ones that are supposed to be loaded for this level.
2403  int n = 0;
2404 
2405  int bm_preloading = 1;
2406 
2407  for (i = 0; i < MAX_BITMAPS; i++) {
2408  if ((bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].type != BM_TYPE_RENDER_TARGET_DYNAMIC) && (bm_bitmaps[i].type != BM_TYPE_RENDER_TARGET_STATIC)) {
2409  if (bm_bitmaps[i].preloaded) {
2410  if (bm_preloading) {
2411  if (!gr_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded == 2))) {
2412  mprintf(("Out of VRAM. Done preloading.\n"));
2413  bm_preloading = 0;
2414  }
2415  } else {
2416  bm_lock(bm_bitmaps[i].handle, (bm_bitmaps[i].used_flags == BMP_AABITMAP) ? 8 : 16, bm_bitmaps[i].used_flags);
2417  if (bm_bitmaps[i].ref_count >= 1) {
2418  bm_unlock( bm_bitmaps[i].handle );
2419  }
2420  }
2421 
2422  n++;
2423 
2425 
2426  if ((bm_bitmaps[i].info.ani.first_frame == 0) || (bm_bitmaps[i].info.ani.first_frame == i)) {
2427 #ifndef NDEBUG
2428  memset(busy_text, 0, sizeof(busy_text));
2429 
2430  strcat_s(busy_text, "** BmpMan: ");
2431  strcat_s(busy_text, bm_bitmaps[i].filename);
2432  strcat_s(busy_text, " **");
2433 
2434  game_busy(busy_text);
2435 #else
2436  game_busy();
2437 #endif
2438  }
2439  } else {
2440  bm_unload_fast(bm_bitmaps[i].handle);
2441  }
2442  }
2443  }
2444 
2445  nprintf(("BmpInfo", "BMPMAN: Loaded %d bitmaps that are marked as used for this level.\n", n));
2446 
2447  int total_bitmaps = 0;
2448  for (i = 0; i < MAX_BITMAPS; i++) {
2449  if (bm_bitmaps[i].type != BM_TYPE_NONE) {
2450  total_bitmaps++;
2451  }
2452  if (bm_bitmaps[i].type == BM_TYPE_USER) {
2453  mprintf(("User bitmap '%s'\n", bm_bitmaps[i].filename));
2454  }
2455  }
2456 
2457  mprintf(("Bmpman: %d/%d bitmap slots in use.\n", total_bitmaps, MAX_BITMAPS));
2458 
2459  Bm_paging = 0;
2460 }
2461 
2462 void bm_page_in_texture(int bitmapnum, int nframes) {
2463  int i;
2464  int n = bitmapnum % MAX_BITMAPS;
2465 
2466  if (bitmapnum < 0)
2467  return;
2468 
2469  Assertion((bm_bitmaps[n].handle == bitmapnum), "bitmapnum = %i, n = %i, bm_bitmaps[n].handle = %i", bitmapnum, n, bm_bitmaps[n].handle);
2470 
2471  if (nframes <= 0) {
2472  if ((bm_bitmaps[n].type == BM_TYPE_ANI) || (bm_bitmaps[n].type == BM_TYPE_EFF))
2473  nframes = bm_bitmaps[n].info.ani.num_frames;
2474  else
2475  nframes = 1;
2476  }
2477 
2478  for (i = 0; i < nframes; i++) {
2479  bm_bitmaps[n + i].preloaded = 1;
2480 
2481  bm_bitmaps[n + i].preload_count++;
2482 
2483  bm_bitmaps[n + i].used_flags = BMP_TEX_OTHER;
2484 
2485  //check if its compressed
2486  switch (bm_bitmaps[n + i].comp_type) {
2487  case BM_TYPE_NONE:
2488  continue;
2489 
2490  case BM_TYPE_DXT1:
2491  bm_bitmaps[n + i].used_flags = BMP_TEX_DXT1;
2492  continue;
2493 
2494  case BM_TYPE_DXT3:
2495  bm_bitmaps[n + i].used_flags = BMP_TEX_DXT3;
2496  continue;
2497 
2498  case BM_TYPE_DXT5:
2499  bm_bitmaps[n + i].used_flags = BMP_TEX_DXT5;
2500  continue;
2501 
2502  case BM_TYPE_CUBEMAP_DXT1:
2503  case BM_TYPE_CUBEMAP_DXT3:
2504  case BM_TYPE_CUBEMAP_DXT5:
2505  bm_bitmaps[n + i].used_flags = BMP_TEX_CUBEMAP;
2506  continue;
2507 
2508  default:
2509  continue;
2510  }
2511  }
2512 }
2513 
2514 void bm_page_in_xparent_texture(int bitmapnum, int nframes) {
2515  int i;
2516  int n = bitmapnum % MAX_BITMAPS;
2517 
2518  if (n == -1)
2519  return;
2520 
2521  Assert(bm_bitmaps[n].handle == bitmapnum);
2522 
2523  for (i = 0; i < nframes; i++) {
2524  bm_bitmaps[n + i].preloaded = 3;
2525 
2526  bm_bitmaps[n + i].preload_count++;
2527 
2528  bm_bitmaps[n + i].used_flags = BMP_TEX_XPARENT;
2529 
2530  //check if its compressed
2531  switch (bm_bitmaps[n + i].comp_type) {
2532  case BM_TYPE_NONE:
2533  continue;
2534 
2535  case BM_TYPE_DXT1:
2536  bm_bitmaps[n + i].used_flags = BMP_TEX_DXT1;
2537  continue;
2538 
2539  case BM_TYPE_DXT3:
2540  bm_bitmaps[n + i].used_flags = BMP_TEX_DXT3;
2541  continue;
2542 
2543  case BM_TYPE_DXT5:
2544  bm_bitmaps[n + i].used_flags = BMP_TEX_DXT5;
2545  continue;
2546 
2547  case BM_TYPE_CUBEMAP_DXT1:
2548  case BM_TYPE_CUBEMAP_DXT3:
2549  case BM_TYPE_CUBEMAP_DXT5:
2550  bm_bitmaps[n + i].used_flags = BMP_TEX_CUBEMAP;
2551  continue;
2552 
2553  default:
2554  continue;
2555  }
2556  }
2557 }
2558 
2559 bool bm_page_out(int handle) {
2560  int n = handle % MAX_BITMAPS;
2561 
2562  Assert(n >= 0);
2563  Assert(handle == bm_bitmaps[n].handle);
2564 
2565  // in case it's already been released
2566  if (bm_bitmaps[n].type == BM_TYPE_NONE)
2567  return 0;
2568 
2569  // it's possible to hit < 0 here when model_page_out_textures() is
2570  // called from anywhere other than in a mission
2571  if (bm_bitmaps[n].preload_count > 0) {
2572  nprintf(("BmpMan",
2573  "PAGE-OUT: %s - preload_count remaining: %d\n",
2574  bm_bitmaps[n].filename,
2575  bm_bitmaps[n].preload_count));
2576 
2577  // lets decrease it for next time around
2578  bm_bitmaps[n].preload_count--;
2579 
2580  return 0;
2581  }
2582 
2583  return (bm_unload(handle) == 1);
2584 }
2585 
2587 #ifdef BMPMAN_NDEBUG
2588  int i;
2589 
2590  for (i = 0; i<MAX_BITMAPS; i++) {
2591  if (bm_bitmaps[i].type != BM_TYPE_NONE) {
2592  if (bm_bitmaps[i].data_size) {
2593  nprintf(("BMP DEBUG", "BMPMAN = num: %d, name: %s, handle: %d - (%s) size: %.3fM\n", i, bm_bitmaps[i].filename, bm_bitmaps[i].handle, bm_bitmaps[i].data_size ? NOX("*LOCKED*") : NOX(""), ((float)bm_bitmaps[i].data_size / 1024.0f) / 1024.0f));
2594  } else {
2595  nprintf(("BMP DEBUG", "BMPMAN = num: %d, name: %s, handle: %d\n", i, bm_bitmaps[i].filename, bm_bitmaps[i].handle));
2596  }
2597  }
2598  }
2599  nprintf(("BMP DEBUG", "BMPMAN = LOCKED memory usage: %.3fM\n", ((float)bm_texture_ram / 1024.0f) / 1024.0f));
2600 #endif
2601 }
2602 
2603 int bm_release(int handle, int clear_render_targets) {
2604  Assert(handle >= 0);
2605 
2606  bitmap_entry *be;
2607 
2608  int n = handle % MAX_BITMAPS;
2609 
2610  Assert((n >= 0) && (n < MAX_BITMAPS));
2611  be = &bm_bitmaps[n];
2612 
2613  if (be->type == BM_TYPE_NONE) {
2614  return 0; // Already been released?
2615  }
2616 
2617  Assertion(be->handle == handle, "Invalid bitmap handle number %d (expected %d) for %s passed to bm_release()\n", be->handle, handle, be->filename);
2618 
2619  if (!clear_render_targets && ((be->type == BM_TYPE_RENDER_TARGET_STATIC) || (be->type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
2620  nprintf(("BmpMan", "Tried to release a render target!\n"));
2621  return 0;
2622  }
2623 
2624  // If it is locked, cannot free it.
2625  if (be->ref_count != 0) {
2626  nprintf(("BmpMan", "Tried to release %s that has a lock count of %d.. not releasing\n", be->filename, be->ref_count));
2627  return 0;
2628  }
2629 
2630  // kind of like ref_count except it gets around the lock/unlock usage problem
2631  // this gets set for each bm_load() call so we can make sure and not unload it
2632  // from memory, even if we *can*, until it's really not needed anymore
2633  if (be->load_count > 0)
2634  be->load_count--;
2635 
2636  if (be->load_count != 0) {
2637  nprintf(("BmpMan", "Tried to release %s that has a load count of %d.. not releasing\n", be->filename, be->load_count + 1));
2638  return 0;
2639  }
2640 
2641  if (be->type != BM_TYPE_USER) {
2642  nprintf(("BmpMan", "Releasing bitmap %s in slot %i with handle %i\n", be->filename, n, handle));
2643  }
2644 
2645  // be sure that all frames of an ani are unloaded - taylor
2646  if ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF)) {
2647  int i, first = be->info.ani.first_frame, total = bm_bitmaps[first].info.ani.num_frames;
2648 
2649  for (i = 0; i < total; i++) {
2650  bm_free_data(first + i, true); // clears flags, bbp, data, etc
2651 
2652  memset(&bm_bitmaps[first + i], 0, sizeof(bitmap_entry));
2653 
2654  bm_bitmaps[first + i].type = BM_TYPE_NONE;
2655  bm_bitmaps[first + i].comp_type = BM_TYPE_NONE;
2656  bm_bitmaps[first + i].dir_type = CF_TYPE_ANY;
2657  // Fill in bogus structures!
2658 
2659  // For debugging:
2660  strcpy_s(bm_bitmaps[first + i].filename, "IVE_BEEN_RELEASED!");
2661  bm_bitmaps[first + i].signature = 0xDEADBEEF; // a unique signature identifying the data
2662  bm_bitmaps[first + i].palette_checksum = 0xDEADBEEF; // checksum used to be sure bitmap is in current palette
2663 
2664  // bookeeping
2665  bm_bitmaps[first + i].ref_count = -1; // Number of locks on bitmap. Can't unload unless ref_count is 0.
2666 
2667  // Stuff needed for animations
2668  bm_bitmaps[first + i].info.ani.first_frame = -1;
2669 
2670  bm_bitmaps[first + i].handle = -1;
2671  }
2672  } else {
2673  bm_free_data(n, true); // clears flags, bbp, data, etc
2674 
2675  memset(&bm_bitmaps[n], 0, sizeof(bitmap_entry));
2676 
2677  bm_bitmaps[n].type = BM_TYPE_NONE;
2678  bm_bitmaps[n].comp_type = BM_TYPE_NONE;
2679  bm_bitmaps[n].dir_type = CF_TYPE_ANY;
2680  // Fill in bogus structures!
2681 
2682  // For debugging:
2683  strcpy_s(bm_bitmaps[n].filename, "IVE_BEEN_RELEASED!");
2684  bm_bitmaps[n].signature = 0xDEADBEEF; // a unique signature identifying the data
2685  bm_bitmaps[n].palette_checksum = 0xDEADBEEF; // checksum used to be sure bitmap is in current palette
2686 
2687  // bookeeping
2688  bm_bitmaps[n].ref_count = -1; // Number of locks on bitmap. Can't unload unless ref_count is 0.
2689 
2690  // Stuff needed for animations
2691  bm_bitmaps[n].info.ani.first_frame = -1;
2692 
2693  bm_bitmaps[n].handle = -1;
2694  }
2695 
2696  return 1;
2697 }
2698 
2699 int bm_reload(int bitmap_handle, const char* filename) {
2700  if (!bm_inited)
2701  bm_init();
2702 
2703  // if no file was passed then get out now
2704  if ((filename == NULL) || (strlen(filename) <= 0))
2705  return -1;
2706 
2707  int bitmapnum = bitmap_handle % MAX_BITMAPS;
2708 
2709  if (bm_bitmaps[bitmapnum].type == BM_TYPE_NONE)
2710  return -1;
2711 
2712  if (bm_bitmaps[bitmapnum].ref_count) {
2713  nprintf(("BmpMan", "Trying to reload a bitmap that is still locked. Filename: %s, ref_count: %d", bm_bitmaps[bitmapnum].filename, bm_bitmaps[bitmapnum].ref_count));
2714  return -1;
2715  }
2716 
2717  strcpy_s(bm_bitmaps[bitmapnum].filename, filename);
2718  return bitmap_handle;
2719 }
2720 
2726 
2727  // setup pointers
2729  // should always assume that 16-bit is the default request
2731 }
2732 
2738 
2739  // setup pointers
2741  // should always assume that 16-bit is the default request
2743 }
2744 
2750 
2751  // setup pointers
2753  // should always assume that 16-bit is the default request
2755 }
2756 
2757 void bm_set_components_argb_16_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av) {
2758  if (*av == 0) {
2759  *((unsigned short*)pixel) = (unsigned short)Gr_current_green->mask;
2760  return;
2761  }
2762 
2763  *((unsigned short*)pixel) = (unsigned short)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
2764  *((unsigned short*)pixel) |= (unsigned short)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
2765  *((unsigned short*)pixel) |= (unsigned short)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
2766 }
2767 
2768 void bm_set_components_argb_16_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av) {
2769  if (*av == 0) {
2770  *((unsigned short*)pixel) = 0;
2771  return;
2772  }
2773 
2774  *((unsigned short*)pixel) = (unsigned short)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
2775  *((unsigned short*)pixel) |= (unsigned short)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
2776  *((unsigned short*)pixel) |= (unsigned short)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
2777  *((unsigned short*)pixel) |= (unsigned short)(Gr_current_alpha->mask);
2778 }
2779 
2780 void bm_set_components_argb_32_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av) {
2781  if (*av == 0) {
2782  *((unsigned int*)pixel) = (unsigned int)Gr_current_green->mask;
2783  return;
2784  }
2785 
2786  *((unsigned int*)pixel) = (unsigned int)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
2787  *((unsigned int*)pixel) |= (unsigned int)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
2788  *((unsigned int*)pixel) |= (unsigned int)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
2789 }
2790 
2791 void bm_set_components_argb_32_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av) {
2792  if (*av == 0) {
2793  *((unsigned int*)pixel) = 0;
2794  return;
2795  }
2796 
2797  *((unsigned int*)pixel) = (unsigned int)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
2798  *((unsigned int*)pixel) |= (unsigned int)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
2799  *((unsigned int*)pixel) |= (unsigned int)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
2800  *((unsigned int*)pixel) |= (unsigned int)(Gr_current_alpha->mask);
2801 }
2802 
2804  Assert((mode >= 0) && (mode <= 2));
2805 
2806  CLAMP(mode, 0, 2);
2807  Bm_low_mem = mode;
2808 }
2809 
2810 bool bm_set_render_target(int handle, int face) {
2811  int n = handle % MAX_BITMAPS;
2812 
2813  if (n >= 0) {
2814  Assert(handle == bm_bitmaps[n].handle);
2815 
2816  if ((bm_bitmaps[n].type != BM_TYPE_RENDER_TARGET_STATIC) && (bm_bitmaps[n].type != BM_TYPE_RENDER_TARGET_DYNAMIC)) {
2817  // odds are that someone passed a normal texture created with bm_load()
2818  mprintf(("Trying to set invalid bitmap (slot: %i, handle: %i) as render target!\n", n, handle));
2819  return false;
2820  }
2821  }
2822 
2823  if (gr_bm_set_render_target(n, face)) {
2824  if (gr_screen.rendering_to_texture == -1) {
2825  //if we are moving from the back buffer to a texture save whatever the current settings are
2828 
2831 
2834 
2837 
2840  }
2841 
2842  if (n < 0) {
2845 
2848 
2851 
2854 
2857  } else {
2858  gr_screen.max_w = bm_bitmaps[n].bm.w;
2859  gr_screen.max_h = bm_bitmaps[n].bm.h;
2860 
2861  gr_screen.max_w_unscaled = bm_bitmaps[n].bm.w;
2862  gr_screen.max_h_unscaled = bm_bitmaps[n].bm.h;
2863 
2864  gr_screen.max_w_unscaled_zoomed = bm_bitmaps[n].bm.w;
2865  gr_screen.max_h_unscaled_zoomed = bm_bitmaps[n].bm.h;
2866 
2867  gr_screen.center_w = bm_bitmaps[n].bm.w;
2868  gr_screen.center_h = bm_bitmaps[n].bm.h;
2869 
2872  }
2873 
2876 
2877  gr_reset_clip();
2878 
2879  if (gr_screen.mode == GR_OPENGL) {
2880  extern void opengl_setup_viewport();
2882  }
2883 
2884  return true;
2885  }
2886 
2887  return false;
2888 }
2889 
2890 int bm_unload(int handle, int clear_render_targets, bool nodebug) {
2891  bitmap_entry *be;
2892  bitmap *bmp;
2893 
2894  int n = handle % MAX_BITMAPS;
2895 
2896  Assert((n >= 0) && (n < MAX_BITMAPS));
2897  be = &bm_bitmaps[n];
2898  bmp = &be->bm;
2899 
2900  if (!clear_render_targets && ((be->type == BM_TYPE_RENDER_TARGET_STATIC) || (be->type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
2901  return -1;
2902  }
2903 
2904  if (be->type == BM_TYPE_NONE) {
2905  return -1; // Already been released
2906  }
2907 
2908  Assert(be->handle == handle); // INVALID BITMAP HANDLE!
2909 
2910  // If it is locked, cannot free it.
2911  if (be->ref_count != 0 && !nodebug) {
2912  nprintf(("BmpMan", "Tried to unload %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
2913  return 0;
2914  }
2915 
2916  // kind of like ref_count except it gets around the lock/unlock usage problem
2917  // this gets set for each bm_load() call so we can make sure and not unload it
2918  // from memory, even if we *can*, until it's really not needed anymore
2919  if (!Bm_ignore_load_count) {
2920  if (be->load_count > 0)
2921  be->load_count--;
2922 
2923  if (be->load_count != 0 && !nodebug) {
2924  nprintf(("BmpMan", "Tried to unload %s that has a load count of %d.. not unloading\n", be->filename, be->load_count + 1));
2925  return 0;
2926  }
2927  }
2928 
2929  // be sure that all frames of an ani are unloaded - taylor
2930  if ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF)) {
2931  int i, first = be->info.ani.first_frame;
2932 
2933  // for the unload all case, don't try to unload every frame of every frame
2934  // all additional frames automatically get unloaded with the first one
2935  if ((n > be->info.ani.first_frame) && (bm_bitmaps[first].bm.data == 0))
2936  return 1;
2937 
2938  for (i = 0; i < bm_bitmaps[first].info.ani.num_frames; i++) {
2939  if (!nodebug)
2940  nprintf(("BmpMan", "Unloading %s frame %d. %dx%dx%d\n", be->filename, i, bmp->w, bmp->h, bmp->bpp));
2941  bm_free_data(first + i); // clears flags, bbp, data, etc
2942  }
2943  } else {
2944  if (!nodebug)
2945  nprintf(("BmpMan", "Unloading %s. %dx%dx%d\n", be->filename, bmp->w, bmp->h, bmp->bpp));
2946  bm_free_data(n); // clears flags, bbp, data, etc
2947  }
2948 
2949  return 1;
2950 }
2951 
2953  int i;
2954 
2955  // since bm_unload_all() should only be called from game_shutdown() it should be
2956  // safe to ignore load_count's and unload anyway
2957  Bm_ignore_load_count = 1;
2958 
2959  for (i = 0; i < MAX_BITMAPS; i++) {
2960  if (bm_bitmaps[i].type != BM_TYPE_NONE) {
2961  bm_unload(bm_bitmaps[i].handle, 1);
2962  }
2963  }
2964 
2965  Bm_ignore_load_count = 0;
2966 }
2967 
2968 int bm_unload_fast(int handle, int clear_render_targets) {
2969  bitmap_entry *be;
2970  bitmap *bmp;
2971 
2972  int n = handle % MAX_BITMAPS;
2973 
2974  Assert((n >= 0) && (n < MAX_BITMAPS));
2975  be = &bm_bitmaps[n];
2976  bmp = &be->bm;
2977 
2978  if (be->type == BM_TYPE_NONE) {
2979  return -1; // Already been released
2980  }
2981 
2982  if (be->type == BM_TYPE_USER) {
2983  return -1;
2984  }
2985 
2986  if (!clear_render_targets && ((be->type == BM_TYPE_RENDER_TARGET_STATIC) || (be->type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
2987  return -1;
2988  }
2989 
2990  // If it is locked, cannot free it.
2991  if (be->ref_count != 0) {
2992  nprintf(("BmpMan", "Tried to unload_fast %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
2993  return 0;
2994  }
2995 
2996  Assert(be->handle == handle); // INVALID BITMAP HANDLE!
2997 
2998  // unlike bm_unload(), we handle each frame of an animation separately, for safer use in the graphics API
2999  nprintf(("BmpMan", "Fast-unloading %s. %dx%dx%d\n", be->filename, bmp->w, bmp->h, bmp->bpp));
3000  bm_free_data_fast(n); // clears flags, bbp, data, etc
3001 
3002  return 1;
3003 }
3004 
3005 void bm_unlock(int handle) {
3006  bitmap_entry *be;
3007 
3008  if (!bm_inited) bm_init();
3009 
3010  int bitmapnum = handle % MAX_BITMAPS;
3011 
3012 #ifndef NDEBUG
3013  if (bm_bitmaps[bitmapnum].handle != handle) {
3014  mprintf(("bm_unlock - %s: bm_bitmaps[%d].handle = %d, handle = %d\n", bm_bitmaps[bitmapnum].filename, bitmapnum, bm_bitmaps[bitmapnum].handle, handle));
3015  }
3016 #endif
3017 
3018  Assert(bm_bitmaps[bitmapnum].handle == handle); // INVALID BITMAP HANDLE
3019 
3020  Assert((bitmapnum >= 0) && (bitmapnum < MAX_BITMAPS));
3021 
3022  be = &bm_bitmaps[bitmapnum];
3023 
3024  be->ref_count--;
3025  Assert(be->ref_count >= 0); // Trying to unlock data more times than lock was called!!!
3026 }
3027 
3028 void bm_update_memory_used(int n, int size)
3029 {
3030  Assert( (n >= 0) && (n < MAX_BITMAPS) );
3031  Assert( size >= 0 );
3032 
3033 #ifdef BMPMAN_NDEBUG
3034  Assert( bm_bitmaps[n].data_size == 0 );
3035  bm_bitmaps[n].data_size += size;
3036  bm_texture_ram += size;
3037 #endif
3038 }
3039 
3040 int find_block_of(int n)
3041 {
3042  int i, cnt = 0, nstart = 0;
3043 
3044  if (n < 1) {
3045  Int3();
3046  return -1;
3047  }
3048 
3049  for (i = 0; i < MAX_BITMAPS; i++) {
3050  if (bm_bitmaps[i].type == BM_TYPE_NONE) {
3051  if (cnt == 0)
3052  nstart = i;
3053 
3054  cnt++;
3055  } else {
3056  cnt = 0;
3057  }
3058 
3059  if (cnt == n)
3060  return nstart;
3061  }
3062 
3063  return -1;
3064 }
void gr_rect(int x, int y, int w, int h, int resize_mode)
Definition: 2d.cpp:2068
cfbp dir_type
Definition: cfile.cpp:1069
void bm_unlock(int handle)
Unlocks a bitmap.
Definition: bmpman.cpp:3005
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
int save_center_offset_x
Definition: 2d.h:369
ubyte bpp
Requested bitdepth of each pixel. ( 7, 8, 15, 16, 24, 32)
Definition: bmpman.h:106
#define EFF_FILENAME_CHECK
Definition: bmpman.cpp:49
int bm_get_next_handle()
Gets the next available bitmap slot.
Definition: bmpman.cpp:820
int height
Definition: packunpack.h:44
const char * bm_ext_list[]
List of extensions for those types.
Definition: bmpman.cpp:69
int i
Definition: multi_pxo.cpp:466
#define PNG_ERROR_INVALID
Definition: pngutils.h:7
#define vm_free(ptr)
Definition: pstypes.h:548
generic DDS cubemap (uncompressed cubemap surface)
Definition: bmpman.h:91
int pcx_read_bitmap(const char *real_filename, ubyte *org_data, ubyte *pal, int byte_size, int aabitmap, int nondark, int cf_type)
Definition: pcxutils.cpp:217
bool bm_page_out(int handle)
Unloads the bitmap indexed by handle that was previously paged-in.
Definition: bmpman.cpp:2559
color_gun Gr_ta_alpha
Definition: 2d.cpp:50
uint bm_get_signature(int handle)
Returns a unique signiature for the bitmap indexed by handle.
Definition: bmpman.cpp:869
#define gr_preload
Definition: 2d.h:848
#define gr_clear
Definition: 2d.h:749
void bm_print_bitmaps()
(DEBUG) Prints all loaded bitmaps to an outwindow
Definition: bmpman.cpp:2586
int offset
Definition: packunpack.h:31
#define TCACHE_TYPE_COMPRESSED
Definition: grinternal.h:54
void bm_lock_dds(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
Definition: bmpman.cpp:1980
#define BMP_TEX_DXT3
dxt3 compressed 8r8g8b4a (32bit)
Definition: bmpman.h:56
#define F1_0
Definition: fix.h:15
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
void gr_flip()
Definition: 2d.cpp:2113
int num_keys
Definition: packunpack.h:49
int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *height, int *bpp, int *compression_type, int *levels, int *size, ubyte *palette)
Definition: ddsutils.cpp:30
int dir_type
which directory this was loaded from (to skip other locations with same name)
Definition: bm_internal.h:62
color_gun Gr_t_red
Definition: 2d.cpp:49
#define BMP_TEX_ANY
Any texture.
Definition: bmpman.h:63
int cfread(void *buf, int elsize, int nelem, CFILE *fp)
color_gun Gr_ta_blue
Definition: 2d.cpp:50
bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type)
Loads and parses an .EFF.
Definition: bmpman.cpp:1239
struct bm_extra_info::@6 user
int shift
Definition: grinternal.h:29
std::basic_stringstream< char, std::char_traits< char >, std::allocator< char > > SCP_stringstream
Definition: vmallocator.h:23
int mode
Definition: 2d.h:371
#define MAX_PATH
color_gun Gr_ta_red
Definition: 2d.cpp:50
void multi_send_anti_timeout_ping()
Definition: multiutil.cpp:4171
PCX.
Definition: bmpman.h:75
int save_max_h_unscaled
Definition: 2d.h:366
size_t mem_taken
How much memory does this bitmap use? - UnknownPlayer.
Definition: bm_internal.h:65
void bm_set_components_argb_16_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
Sets the 16bpp texture pixel to the specified RGBA value.
Definition: bmpman.cpp:2768
int Bm_paging
Bool type that indicates if BMPMAN is currently paging.
Definition: bmpman.cpp:65
int targa_read_header(const char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *palette)
Definition: tgautils.cpp:361
24-bit cubemap (compressed cubemap surface)
Definition: bmpman.h:92
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
ubyte true_bpp
The image's actual bitdepth.
Definition: bmpman.h:107
Assert(pm!=NULL)
int targa_read_bitmap(const char *real_filename, ubyte *image_data, ubyte *palette, int dest_size, int cf_type)
Definition: tgautils.cpp:503
ubyte flags
Various texture type flags.
Definition: bmpman.h:108
#define mprintf(args)
Definition: pstypes.h:238
__inline int gr_bm_set_render_target(int n, int face=-1)
Definition: 2d.h:866
int png_read_bitmap(const char *real_filename, ubyte *image_data, ubyte *bpp, int dest_size, int cf_type)
Definition: pngutils.cpp:133
void bm_page_in_stop()
Tells bmpman to stop paging (?)
Definition: bmpman.cpp:2393
int max_h_unscaled
Definition: 2d.h:361
int bm_get_info(int handle, int *w, int *h, ubyte *flags, int *nframes, int *fps)
Gets info on the bitmap indexed by handle.
Definition: bmpman.cpp:769
int bm_texture_ram
how many bytes of textures are used.
Definition: bmpman.cpp:64
#define DDS_CUBEMAP_DXT3
Definition: ddsutils.h:28
int center_h
Definition: 2d.h:363
int total_frames
Definition: packunpack.h:45
const int BM_ANI_NUM_TYPES
Calculated number of bitmap animation types.
Definition: bmpman.cpp:74
GLclampf f
Definition: Glext.h:7097
#define INTEL_SHORT(x)
Definition: pstypes.h:389
#define PCX_ERROR_NONE
Definition: pcxutils.h:25
#define SIZE_T_ARG
Definition: clang.h:61
int bits_per_pixel
Definition: 2d.h:374
BM_TYPE type
PCX, USER, ANI, etc.
Definition: bm_internal.h:58
int bm_load_duplicate(const char *filename)
Reloads a bitmap as a duplicate.
Definition: bmpman.cpp:1668
Definition: cfile.h:28
struct bm_extra_info::@5 ani
int center_offset_y
Definition: 2d.h:364
#define PNG_ERROR_NONE
Definition: pngutils.h:8
#define Assertion(expr, msg,...)
Definition: clang.h:41
size_t bm_get_size(int handle)
Gets the size, in bytes, taken up by the bitmap indexed by handle.
Definition: bmpman.cpp:878
#define BMP_TEX_NONCOMP
Non-compressed textures.
Definition: bmpman.h:62
ubyte used_flags
What flags it was accessed thru.
Definition: bm_internal.h:71
void bm_page_in_start()
Tells bmpman to start keeping track of what bitmaps are used where.
Definition: bmpman.cpp:2372
enum_h * u
Definition: lua.cpp:12649
uint signature
a unique signature identifying the data
Definition: bm_internal.h:53
int cf_find_file_location_ext(const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out=0, char *pack_filename=NULL, int *size=NULL, int *offset=NULL, bool localize=false)
int bm_get_tcache_type(int num)
Gets the correct TCACHE_TYPE for compressed graphics (uncompressed are assumed TCACHE_TYPE_NORMAL) ...
Definition: bmpman.cpp:887
GLenum mode
Definition: Glext.h:5794
int save_max_w
Definition: 2d.h:365
void bm_update_memory_used(int n, int size)
(DEBUG) Similar to bm_malloc, but only updates how much memory is used
Definition: bmpman.cpp:3028
int center_w
Definition: 2d.h:363
void bm_lock_pcx(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
Definition: bmpman.cpp:2084
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
int key
int png_read_header(const char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *palette)
Definition: pngutils.cpp:38
#define BMP_TEX_DXT5
dxt5 compressed 8r8g8b8a (32bit)
Definition: bmpman.h:57
GLsizeiptr size
Definition: Glext.h:5496
int max_w_unscaled
Definition: 2d.h:361
#define Int3()
Definition: pstypes.h:292
bool bm_has_alpha_channel(int handle)
Checks to see if the indexed bitmap has an alpha channel.
Definition: bmpman.cpp:903
#define gr_bm_create
Definition: 2d.h:859
color_gun * Gr_current_green
Definition: 2d.cpp:51
No type.
Definition: bmpman.h:73
void free_anim_instance(anim_instance *inst)
Definition: packunpack.cpp:68
void bm_page_in_xparent_texture(int bitmapnum, int nframes)
Marks a textures as being used for level and is transparant.
Definition: bmpman.cpp:2514
#define cfopen_special(...)
Definition: cfile.h:140
short h
Height, in number of pixels.
Definition: bmpman.h:104
32 bit with 8 bit alpha
Definition: bmpman.h:90
void bm_init()
Initilizes the bitmap manager.
Definition: bmpman.cpp:916
int bm_unload_fast(int handle, int clear_render_targets)
Quickly unloads a bitmap's data, ignoring the load_count.
Definition: bmpman.cpp:2968
int bm_release(int handle, int clear_render_targets)
Frees both a bitmap's data and it's associated slot.
Definition: bmpman.cpp:2603
#define GR_OPENGL
Definition: 2d.h:648
in-house ANI format
Definition: bmpman.h:80
int NORMMAP
Normal mapping.
Definition: bmpman.cpp:60
#define BMP_FLAG_RENDER_TARGET_STATIC
Texture is a static type.
Definition: bmpman.h:66
void bm_lock_ani(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
Definition: bmpman.cpp:1860
void BM_SELECT_TEX_FORMAT()
Sets bm_set_components and bm_get_components to reference texture format functions.
Definition: bmpman.cpp:2745
GLenum type
Definition: Gl.h:1492
#define gr_bm_make_render_target
Definition: 2d.h:864
#define BMP_AABITMAP
antialiased bitmap
Definition: bmpman.h:52
ubyte flags
For user bitmaps, Flags passed to bm_create.
Definition: bm_internal.h:45
#define JPEG_ERROR_INVALID
Definition: jpgutils.h:19
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
Loads a bitmap sequance so we can draw with it.
Definition: bmpman.cpp:1420
#define CLAMP(x, min, max)
Definition: pstypes.h:488
int HEIGHTMAP
Height map for normal mapping.
Definition: bmpman.cpp:61
const BM_TYPE bm_type_list[]
List of valid bitmap types.
Definition: bmpman.cpp:68
GLint GLsizei width
Definition: Gl.h:1505
ubyte * palette
Pointer to this bitmap's palette (if it has one).
Definition: bmpman.h:110
char name[MAX_PATH_LEN]
Definition: packunpack.h:41
void game_busy(const char *filename=NULL)
Definition: systemvars.cpp:173
void gr_set_color(int r, int g, int b)
Definition: 2d.cpp:1188
int handle
Handle = id*MAX_BITMAPS + bitmapnum.
Definition: bm_internal.h:55
int jpeg_read_bitmap(const char *real_filename, ubyte *image_data, ubyte *palette, int dest_size, int cf_type)
Definition: jpgutils.cpp:167
int bm_is_valid(int handle)
Checks if the bitmap indexed by handle is valid.
Definition: bmpman.cpp:1006
key_frame * keys
Definition: packunpack.h:50
GLenum GLuint GLint GLenum face
Definition: Glext.h:6586
void opengl_setup_viewport()
Definition: gropengl.cpp:1297
Definition: bm_internal.h:49
int strextcmp(const char *s1, const char *s2)
Definition: parselo.cpp:4013
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
#define gr_reset_clip
Definition: 2d.h:745
int preload_count
how many times this gets used in game, for unlocking
Definition: bm_internal.h:70
GLintptr offset
Definition: Glext.h:5497
#define JPEG_ERROR_NONE
Definition: jpgutils.h:20
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
const char * bm_ani_ext_list[]
List of extensions for those types.
Definition: bmpman.cpp:73
unsigned int uint
Definition: pstypes.h:64
#define BMP_TEX_DXT1
dxt1 compressed 8r8g8b1a (24bit)
Definition: bmpman.h:55
void(* bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a)
Functional pointer that references any of the bm_set_components functions.
Definition: bmpman.cpp:76
GLboolean GLboolean g
Definition: Glext.h:5781
32 bit jpeg
Definition: bmpman.h:79
int bm_is_compressed(int num)
Returns the compression type of the bitmap indexed by handle.
Definition: bmpman.cpp:952
#define nprintf(args)
Definition: pstypes.h:239
#define f2i(a)
Definition: fix.h:22
#define BMP_FLAG_CUBEMAP
Texture is a cubemap.
Definition: bmpman.h:68
GLboolean GLboolean GLboolean GLboolean a
Definition: Glext.h:5781
#define DDS_DXT5
Definition: ddsutils.h:25
specifies any type of animated image, the EFF itself is just text
Definition: bmpman.h:81
bitmap_entry bm_bitmaps[MAX_BITMAPS]
Definition: bmpman.cpp:85
char * filename
int GLOWMAP
References a map that is a fully lit version of its index -Bobboau.
Definition: bmpman.cpp:57
int Use_compressed_textures
Definition: ddsutils.cpp:20
int mask
Definition: grinternal.h:31
PNG.
Definition: bmpman.h:78
void stuff_string(char *outstr, int type, int len, char *terminators)
Definition: parselo.cpp:1189
void(* bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a)
Functional pointer that references any of the bm_set_components_32 functions.
Definition: bmpman.cpp:77
#define w(p)
Definition: modelsinc.h:68
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
int Cmdline_cache_bitmaps
Definition: cmdline.cpp:352
color_gun Gr_ta_green
Definition: 2d.cpp:50
24 bit with switchable alpha
Definition: bmpman.h:88
const char * bm_get_filename(int handle)
Gets the filename of the bitmap indexed by handle, which must exist.
Definition: bmpman.cpp:727
color_gun * Gr_current_red
Definition: 2d.cpp:51
short w
Width, in number of pixels.
Definition: bmpman.h:103
int anim_free(anim *ptr)
Free an animation that was loaded with anim_load().
Definition: animplay.cpp:813
const BM_TYPE bm_ani_type_list[]
List of valid bitmap animation types.
Definition: bmpman.cpp:72
short rowsize
What you need to add to go to next row.
Definition: bmpman.h:105
32-bit cubemap (compressed cubemap surface)
Definition: bmpman.h:94
int width
Definition: packunpack.h:43
int frame_num
Definition: packunpack.h:30
int required_string(const char *pstr)
Definition: parselo.cpp:468
void bm_lock_user(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
Definition: bmpman.cpp:2226
uint palette_checksum
checksum used to be sure bitmap is in current palette
Definition: bm_internal.h:54
char filename[MAX_FILENAME_LEN]
filename for this bitmap
Definition: bm_internal.h:51
Definition: bmpman.h:101
struct bm_extra_info::@5::@7 eff
int first_frame
used for animations – points to index of first frame
Definition: bm_internal.h:29
bitmap * bm_lock(int handle, ubyte bpp, ubyte flags, bool nodebug)
Locks down the bitmap indexed by bitmapnum.
Definition: bmpman.cpp:1754
int optional_string(const char *pstr)
Definition: parselo.cpp:539
in-memory
Definition: bmpman.h:74
void bm_set_components_argb_32_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
Sets the 32bpp screen pixel to the specified RGBA value.
Definition: bmpman.cpp:2780
bool dc_optional_string_either(const char *str1, const char *str2)
Searches for an optional string and it's alias.
#define MONITOR(function_name)
Definition: pstypes.h:454
float get_channel_alpha(float u, float v)
Definition: bmpman.cpp:186
16 or 32 bit targa
Definition: bmpman.h:76
color_gun * Gr_current_blue
Definition: 2d.cpp:51
BM_TYPE
Definition: bmpman.h:71
int pcx_read_header(const char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *pal)
Definition: pcxutils.cpp:40
void bm_get_frame_usage(int *ntotal, int *nnew)
(DEBUG) Gets memory size, in bytes, of the locked bitmaps
Definition: bmpman.cpp:749
#define DDS_CUBEMAP_UNCOMPRESSED
Definition: ddsutils.h:26
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
Definition: parselo.cpp:1995
bool bm_set_render_target(int handle, int face)
(GR function) Calls gr_bm_set_render target for the given bitmap indexed by handle ...
Definition: bmpman.cpp:2810
#define BMP_TEX_OTHER
so we can identify all "normal" textures
Definition: bmpman.h:54
float get_channel_blue(float u, float v)
Definition: bmpman.cpp:176
int bm_is_render_target(int bitmap_id)
Checks to see if the given bitmap indexed by handle is a render target.
Definition: bmpman.cpp:993
int idx
Definition: multiui.cpp:761
#define gr_bm_free_data
Definition: 2d.h:858
int rendering_to_face
Definition: 2d.h:404
void unpause_parse()
Definition: parselo.cpp:3289
void pause_parse()
Definition: parselo.cpp:3272
#define gr_bm_init
Definition: 2d.h:860
void bm_get_palette(int handle, ubyte *pal, char *name)
Gets the palette for a given bitmap indexed by handle, and optionally the filename.
Definition: bmpman.cpp:850
int scale
Definition: grinternal.h:30
int save_max_w_unscaled_zoomed
Definition: 2d.h:367
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
signed char ref_count
Number of locks on bitmap. Can't unload unless ref_count is 0.
Definition: bm_internal.h:60
long fix
Definition: pstypes.h:54
GLclampd n
Definition: Glext.h:7286
unsigned char ubyte
Definition: pstypes.h:62
bitmap_lookup(int bitmap_num)
Definition: bmpman.cpp:109
#define MONITOR_INC(function_name, inc)
Definition: pstypes.h:457
void bm_set_low_mem(int mode)
Sets BMPMAN's memory mode.
Definition: bmpman.cpp:2803
int bm_create(int bpp, int w, int h, void *data, int flags)
Definition: bmpman.cpp:469
const int BM_NUM_TYPES
Calculated number of bitmap types.
Definition: bmpman.cpp:70
int save_center_h
Definition: 2d.h:368
#define DDS_UNCOMPRESSED
Definition: ddsutils.h:22
float get_channel_green(float u, float v)
Definition: bmpman.cpp:163
color_gun Gr_t_blue
Definition: 2d.cpp:49
int max_w
Definition: 2d.h:360
#define NOX(s)
Definition: pstypes.h:473
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
GLbitfield flags
Definition: Glext.h:6722
24/32 bit setup internally as a dynamic render target
Definition: bmpman.h:85
#define vm_malloc(size)
Definition: pstypes.h:547
typedef void(APIENTRY *PFNGLARRAYELEMENTEXTPROC)(GLint i)
void reset_parse(char *text)
Definition: parselo.cpp:3305
#define INTEL_INT(x)
Definition: pstypes.h:388
ubyte gr_palette[256 *3]
Definition: palman.cpp:27
void dc_stuff_int(int *i)
Stuffs an int to the given variable. Supports binary (0b), hexadecimal (0x), and octal (0o) formats...
GLuint const GLchar * name
Definition: Glext.h:5608
int key_getch()
Definition: key.cpp:514
int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
Definition: ddsutils.cpp:275
color_gun Gr_t_alpha
Definition: 2d.cpp:49
int max_w_unscaled_zoomed
Definition: 2d.h:362
void bm_lock_png(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
Definition: bmpman.cpp:2127
void * data
For user bitmaps, this is where the data comes from.
Definition: bm_internal.h:43
int fps
Definition: packunpack.h:56
int bm_load(const char *real_filename)
Loads a bitmap so we can draw with it later.
Definition: bmpman.cpp:1119
int bm_get_cache_slot(int bitmap_id, int separate_ani_frames)
Definition: bmpman.cpp:669
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
void stuff_int(int *i)
Definition: parselo.cpp:2372
color_gun Gr_red
Definition: 2d.cpp:48
#define BMP_TEX_CUBEMAP
a texture made for cubic environment map
Definition: bmpman.h:58
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
int save_center_offset_y
Definition: 2d.h:369
GLuint GLuint num
Definition: Glext.h:9089
void anim_read_header(anim *ptr, CFILE *fp)
Definition: animplay.cpp:607
int last_used
When this bitmap was last used.
Definition: bm_internal.h:56
bitmap bm
Bitmap info.
Definition: bm_internal.h:74
#define DDS_DXT3
Definition: ddsutils.h:24
GLint GLsizei GLsizei height
Definition: Gl.h:1505
#define strcat_s(...)
Definition: safe_strings.h:68
ubyte * anim_get_next_raw_buffer(anim_instance *inst, int xlate_pal, int aabitmap, int bpp)
Definition: packunpack.cpp:127
GLubyte GLubyte GLubyte GLubyte w
Definition: Glext.h:5679
ubyte preloaded
If set, then this was loaded from the lst file.
Definition: bm_internal.h:69
void bm_page_in_aabitmap(int bitmapnum, int nframes)
Marks a texture as being used for this level, and is anti-aliased.
Definition: bmpman.cpp:2354
unsigned int ptr_u
Definition: pstypes.h:57
#define fl2i(fl)
Definition: floating.h:33
void bm_set_components_argb_16_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
Sets the 16bpp screen pixel to the specified RGBA value.
Definition: bmpman.cpp:2757
#define DDS_ERROR_NONE
Definition: ddsutils.h:11
const char * dds_error_string(int code)
Definition: ddsutils.cpp:467
void bm_set_components_argb_32_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
Sets the 32bpp texture pixel to the specified RGBA value.
Definition: bmpman.cpp:2791
void BM_SELECT_ALPHA_TEX_FORMAT()
Sets bm_set_components and bm_get_components to reference texture format functions (with alpha) ...
Definition: bmpman.cpp:2721
void bm_page_in_texture(int bitmapnum, int nframes)
Marks a texture as being used for this level.
Definition: bmpman.cpp:2462
ubyte fps
used for animations – frames per second
Definition: bm_internal.h:32
generic identifier for DDS
Definition: bmpman.h:77
#define BMP_TEX_COMP
Compressed textures.
Definition: bmpman.h:61
screen gr_screen
Definition: 2d.cpp:46
#define TCACHE_TYPE_NORMAL
Definition: grinternal.h:51
#define gr_bm_data
Definition: 2d.h:862
GLint first
Definition: Gl.h:1491
unsigned short ushort
Definition: pstypes.h:63
void bm_lock_jpg(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
Definition: bmpman.cpp:2042
color_gun Gr_alpha
Definition: 2d.cpp:48
color_gun * Gr_current_alpha
Definition: 2d.cpp:51
color_gun Gr_t_green
Definition: 2d.cpp:49
int center_offset_x
Definition: 2d.h:364
GLfloat GLfloat p
Definition: Glext.h:8373
#define F_NAME
Definition: parselo.h:34
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
#define TARGA_ERROR_NONE
Definition: tgautils.h:23
#define LOCATION
Definition: pstypes.h:245
int max_h
Definition: 2d.h:360
GLenum GLsizei GLenum GLenum const GLvoid * data
Definition: Gl.h:1509
color_gun Gr_green
Definition: 2d.cpp:48
24/32 bit setup internally as a static render target
Definition: bmpman.h:84
int save_max_w_unscaled
Definition: 2d.h:366
ptr_u data
Pointer to data, or maybe offset into VRAM.
Definition: bmpman.h:109
int num_mipmaps
number of mipmap levels, we need to read all of them
Definition: bm_internal.h:66
BM_TYPE bm_get_type(int handle)
Returns the image type of the given bitmap handle.
Definition: bmpman.cpp:894
bm_extra_info info
Data for animations and user bitmaps.
Definition: bm_internal.h:76
void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a)
Gets the RGBA components of a pixel according to the selected mode.
Definition: bmpman.cpp:685
int load_count
Definition: bm_internal.h:72
int ENVMAP
References a map that is for environment mapping -Bobboau.
Definition: bmpman.cpp:59
#define i2fl(i)
Definition: floating.h:32
#define MAX_BITMAPS
How many bitmaps the game can handle.
Definition: bmpman.h:48
ubyte bpp
For user bitmaps, this is what format the data is.
Definition: bm_internal.h:44
anim_instance * init_anim_instance(anim *ptr, int bpp)
Definition: packunpack.cpp:28
void * bm_malloc(int n, int size)
Allocates memory for the given handle.
Definition: bmpman.cpp:2339
bool dc_optional_string(const char *pstr)
Searches for an optional string.
int SPECMAP
References a map that is for specular mapping -Bobboau.
Definition: bmpman.cpp:58
void dc_printf(const char *format,...)
Prints the given char string to the debug console.
Definition: console.cpp:358
int bm_load_either(const char *filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
Loads either animation (bm_load_animation) or still image (bm_load)
Definition: bmpman.cpp:1683
#define DDS_CUBEMAP_DXT1
Definition: ddsutils.h:27
#define MAX(a, b)
Definition: pstypes.h:299
#define gr_bm_page_in_start
Definition: 2d.h:861
int bm_unload(int handle, int clear_render_targets, bool nodebug)
Unloads a bitmap's data, but not the bitmap info.
Definition: bmpman.cpp:2890
void bm_clean_slot(int n)
Definition: bmpman.cpp:455
32-bit cubemap (compressed cubemap surface)
Definition: bmpman.h:93
int num_frames
used for animations – number of frames in the animation
Definition: bm_internal.h:30
#define DDS_CUBEMAP_DXT5
Definition: ddsutils.h:29
int MISCMAP
Utility map, to be utilized for various things shader authors can come up with.
Definition: bmpman.cpp:62
int cfclose(CFILE *cfile)
Definition: cfile.cpp:895
int save_max_h_unscaled_zoomed
Definition: 2d.h:367
bool valid()
Definition: bmpman.cpp:139
#define gr_get_bitmap_from_texture
Definition: 2d.h:951
int bm_make_render_target(int width, int height, int flags)
Creates a render target as close to the desired resolution as possible.
Definition: bmpman.cpp:2267
void bm_unload_all()
Unloads all used bitmaps, should only ever be called by game_shutdown()
Definition: bmpman.cpp:2952
#define BMP_TEX_XPARENT
transparent texture
Definition: bmpman.h:53
int jpeg_read_header(const char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *palette)
Definition: jpgutils.cpp:99
int rendering_to_texture
Definition: 2d.h:403
int save_center_w
Definition: 2d.h:368
#define CF_TYPE_ANY
Definition: cfile.h:42
int save_max_h
Definition: 2d.h:365
int bm_get_num_mipmaps(int num)
Gets the number of mipmaps of the indexed texture.
Definition: bmpman.cpp:838
int timer_get_milliseconds()
Definition: timer.cpp:150
#define DDS_DXT1
Definition: ddsutils.h:23
float get_channel_red(float u, float v)
Definition: bmpman.cpp:150
#define stricmp(s1, s2)
Definition: config.h:271
const GLdouble * v
Definition: Glext.h:5322
32 bit with 4 bit alpha
Definition: bmpman.h:89
int max_h_unscaled_zoomed
Definition: 2d.h:362
void bm_lock_tga(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
Definition: bmpman.cpp:2170
GLuint address
Definition: Glext.h:8864
DCF(bm_frag,"Shows BmpMan fragmentation")
Definition: bmpman.cpp:243
BM_TYPE comp_type
What sort of compressed type, BM_TYPE_NONE if not compressed.
Definition: bm_internal.h:59
anim * anim_load(char *real_filename, int cf_dir_type, int file_mapped)
Load an animation. This stores the compressed data, which instances of the animation can reference...
Definition: animplay.cpp:687
int keyframe
used for animations – keyframe info
Definition: bm_internal.h:31
GLint y
Definition: Gl.h:1505
#define strcpy_s(...)
Definition: safe_strings.h:67
void BM_SELECT_SCREEN_FORMAT()
Sets bm_set_components and bm_get_components to reference screen format functions.
Definition: bmpman.cpp:2733
int Is_standalone
Definition: systemvars.cpp:59
color_gun Gr_blue
Definition: 2d.cpp:48
int bm_reload(int bitmap_handle, const char *filename)
Reloads an existing bmpman slot with different bitmap.
Definition: bmpman.cpp:2699
void bm_close()
Closes the bitmap manager, freeing any allocated memory used by bitmaps. Is called at program close...
Definition: bmpman.cpp:459