Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- From a75c0d4b3983d3f3fcf7ab8729f05418cfddd11b Mon Sep 17 00:00:00 2001
- From: Bryan Dunsheng See <bryan.see@live.com>
- Date: Mon, 14 Dec 2015 00:28:53 +0800
- Subject: [PATCH] Cleared unused functions from bmpman code; added ID code
- ---
- code/bmpman/bm_internal.h | 1 +
- code/bmpman/bmpman.cpp | 3655 ++++++++++++++++++++++++---------------------
- code/bmpman/bmpman.h | 833 +++--------
- 3 files changed, 2142 insertions(+), 2347 deletions(-)
- diff --git a/code/bmpman/bm_internal.h b/code/bmpman/bm_internal.h
- index cf324fe..1b2b21b 100644
- --- a/code/bmpman/bm_internal.h
- +++ b/code/bmpman/bm_internal.h
- @@ -48,6 +48,7 @@ union bm_extra_info {
- struct bitmap_entry {
- // identification
- + int id; //!< ID for this bitmap
- char filename[MAX_FILENAME_LEN]; //!< filename for this bitmap
- uint signature; //!< a unique signature identifying the data
- diff --git a/code/bmpman/bmpman.cpp b/code/bmpman/bmpman.cpp
- index e25bb0b..65714b4 100644
- --- a/code/bmpman/bmpman.cpp
- +++ b/code/bmpman/bmpman.cpp
- @@ -1,380 +1,361 @@
- /*
- - * Copyright (C) Volition, Inc. 1999. All rights reserved.
- - *
- - * All source code herein is the property of Volition, Inc. You may not sell
- - * or otherwise commercially exploit the source or things you created based on the
- - * source.
- - *
- +* Copyright (C) Volition, Inc. 1999. All rights reserved.
- +*
- +* All source code herein is the property of Volition, Inc. You may not sell
- +* or otherwise commercially exploit the source or things you created based on the
- +* source.
- +*
- */
- -#ifndef NDEBUG
- -#define BMPMAN_NDEBUG
- -#endif
- -#define BMPMAN_INTERNAL
- +
- +
- +#include <ctype.h>
- +
- +#include "globalincs/pstypes.h"
- #ifdef _WIN32
- -#include <windows.h>
- +#include <windows.h> // for MAX_PATH
- #endif
- -#include "anim/animplay.h"
- -#include "anim/packunpack.h"
- -#include "bmpman/bm_internal.h"
- +#include <limits.h> // for MAX_INT
- +
- #include "bmpman/bmpman.h"
- -#include "ddsutils/ddsutils.h"
- -#include "debugconsole/console.h"
- -#include "globalincs/systemvars.h"
- +#include "pcxutils/pcxutils.h"
- +#include "palman/palman.h"
- #include "graphics/2d.h"
- -#include "graphics/grinternal.h"
- -#include "io/key.h"
- +#include "anim/animplay.h"
- #include "io/timer.h"
- +#include "globalincs/systemvars.h"
- +#include "io/key.h"
- +#include "anim/packunpack.h"
- +#include "graphics/grinternal.h"
- +#include "tgautils/tgautils.h"
- +#include "ship/ship.h"
- +#include "ddsutils/ddsutils.h"
- +#include "cfile/cfile.h"
- +#include "pngutils/pngutils.h"
- #include "jpgutils/jpgutils.h"
- -#include "network/multiutil.h"
- -#include "palman/palman.h"
- #include "parse/parselo.h"
- -#include "pcxutils/pcxutils.h"
- -#include "pngutils/pngutils.h"
- -#include "ship/ship.h"
- -#include "tgautils/tgautils.h"
- +#include "network/multiutil.h"
- +#include "debugconsole/console.h"
- -#include <ctype.h>
- -#include <limits.h>
- +#define BMPMAN_INTERNAL
- +#include "bmpman/bm_internal.h"
- +
- +extern int Cmdline_cache_bitmaps;
- -// --------------------------------------------------------------------------------------------------------------------
- -// Private macros.
- +#ifndef NDEBUG
- +#define BMPMAN_NDEBUG
- +#endif
- -/**
- - * @todo upgrade this to an inline funciton, taking bitmap_entry and const char* as arguments
- - */
- -#define EFF_FILENAME_CHECK { if ( be->type == BM_TYPE_EFF ) strcpy_s( filename, be->info.ani.eff.filename ); else strcpy_s( filename, be->filename ); }
- -// --------------------------------------------------------------------------------------------------------------------
- -// Monitor variables
- -MONITOR(NumBitmapPage)
- -MONITOR(SizeBitmapPage)
- -// --------------------------------------------------------------------------------------------------------------------
- -// Definition of public variables (declared as extern in bmpman.h).
- +// globals
- int GLOWMAP = -1;
- int SPECMAP = -1;
- -int ENVMAP = -1;
- +int ENVMAP = -1;
- int NORMMAP = -1;
- int HEIGHTMAP = -1;
- int MISCMAP = -1;
- +bitmap_entry bm_bitmaps[MAX_BITMAPS];
- +
- int bm_texture_ram = 0;
- +int bm_inited = 0;
- int Bm_paging = 0;
- -// Extension type lists
- -const BM_TYPE bm_type_list[] = { BM_TYPE_DDS, BM_TYPE_TGA, BM_TYPE_PNG, BM_TYPE_JPG, BM_TYPE_PCX };
- -const char *bm_ext_list[] = { ".dds", ".tga", ".png", ".jpg", ".pcx" };
- -const int BM_NUM_TYPES = sizeof(bm_type_list) / sizeof(bm_type_list[0]);
- +// locals
- +static unsigned int Bm_next_signature = 0x1234;
- +static int bm_next_handle = 1;
- +int Bm_low_mem = 0;
- +// Bm_max_ram - How much RAM bmpman can use for textures.
- +// Set to <1 to make it use all it wants.
- +int Bm_max_ram = 0; //16*1024*1024; // Only use 16 MB for textures
- +static int Bm_ignore_duplicates = 0;
- +static int Bm_ignore_load_count = 0;
- -const BM_TYPE bm_ani_type_list[] = { BM_TYPE_EFF, BM_TYPE_ANI };
- -const char *bm_ani_ext_list[] = { ".eff", ".ani" };
- -const int BM_ANI_NUM_TYPES = sizeof(bm_ani_type_list) / sizeof(bm_ani_type_list[0]);
- +#define EFF_FILENAME_CHECK { if ( be->type == BM_TYPE_EFF ) strcpy_s( filename, be->info.ani.eff.filename ); else strcpy_s( filename, be->filename ); }
- -void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
- -void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
- -// --------------------------------------------------------------------------------------------------------------------
- -// Declaration of protected variables (defined in cmdline.cpp).
- -extern int Cmdline_cache_bitmaps;
- -// --------------------------------------------------------------------------------------------------------------------
- -// Definition of public variables (declared as extern in bm_internal.h).
- -bitmap_entry bm_bitmaps[MAX_BITMAPS];
- +// ===========================================
- +// Mode: 0 = High memory
- +// 1 = Low memory ( every other frame of ani's)
- +// 2 = Debug low memory ( only use first frame of each ani )
- +void bm_set_low_mem(int mode)
- +{
- + Assert((mode >= 0) && (mode <= 2));
- -// --------------------------------------------------------------------------------------------------------------------
- -// Definition of private variables at file scope (static).
- -static int bm_inited = 0;
- -static uint Bm_next_signature = 0x1234;
- -static int bm_next_handle = 1;
- -static int Bm_low_mem = 0;
- + CLAMP(mode, 0, 2);
- + Bm_low_mem = mode;
- +}
- -/**
- - * How much RAM bmpman can use for textures.
- - *
- - * @details Set to <1 to make it use all it wants.
- - *
- - * @note was initialized to 16*1024*1024 at some point to "use only 16MB for textures"
- - */
- -static int Bm_max_ram = 0;
- -static int Bm_ignore_duplicates = 0;
- -static int Bm_ignore_load_count = 0;
- +int bm_get_next_handle()
- +{
- + //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;
- + //as bitmaps get allocated and released, bm_next_handle could get there far more often than you'd think.
- + //The check introduced below is intended to replace this behaviour with one that ensures we won't be seeing handle collisions
- + //for a very long time.
- +
- + bm_next_handle++;
- -// --------------------------------------------------------------------------------------------------------------------
- -// Declaration of private functions and templates(declared as static type func(type param);)
- + //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[]),
- + //this check is necessary to ensure we don't start giving out negative handles all of a sudden.
- + if (((bm_next_handle + 1) * MAX_BITMAPS) > INT_MAX)
- + bm_next_handle = 1;
- +
- + return bm_next_handle;
- +}
- -bitmap_lookup::bitmap_lookup(int bitmap_num):
- - Bitmap_data(NULL)
- +/**
- +* Frees a bitmaps data if it can
- +*/
- +static void bm_free_data(int n, bool release = false)
- {
- - if ( !bm_is_valid(bitmap_num) ) return;
- + bitmap_entry *be;
- + bitmap *bmp;
- +
- + Assert((n >= 0) && (n < MAX_BITMAPS));
- +
- + be = &bm_bitmaps[n];
- + bmp = &be->bm;
- +
- + gr_bm_free_data(n, release);
- +
- + // If there isn't a bitmap in this structure, don't
- + // do anything but clear out the bitmap info
- + if (be->type == BM_TYPE_NONE)
- + goto SkipFree;
- - Num_channels = 3;
- + // Don't free up memory for user defined bitmaps, since
- + // BmpMan isn't the one in charge of allocating/deallocing them.
- + if (be->type == BM_TYPE_USER) {
- +#ifdef BMPMAN_NDEBUG
- + if (be->data_size != 0)
- + bm_texture_ram -= be->data_size;
- +#endif
- + goto SkipFree;
- + }
- - if ( bm_has_alpha_channel(bitmap_num) ) {
- - Num_channels = 4;
- + // If this bitmap doesn't have any data to free, skip
- + // the freeing it part of this.
- + if (bmp->data == 0) {
- +#ifdef BMPMAN_NDEBUG
- + if (be->data_size != 0)
- + bm_texture_ram -= be->data_size;
- +#endif
- + goto SkipFree;
- }
- - int n = bitmap_num % MAX_BITMAPS;
- + // Free up the data now!
- +#ifdef BMPMAN_NDEBUG
- + bm_texture_ram -= be->data_size;
- +#endif
- + vm_free((void *)bmp->data);
- - bitmap_entry *be = &bm_bitmaps[n];
- -
- - Width = be->bm.w;
- - Height = be->bm.h;
- + // reset the load_count to at least 1, don't do this in SkipFree though
- + // since the real count ends up wrong
- + be->load_count = 1;
- - Bitmap_data = (float*)vm_malloc(Width * Height * Num_channels * sizeof(float));
- +SkipFree:
- - gr_get_bitmap_from_texture((void*)Bitmap_data, bitmap_num);
- + // Clear out & reset the bitmap data structure
- + bmp->flags = 0;
- + bmp->bpp = 0;
- + bmp->data = 0;
- + bmp->palette = NULL;
- +#ifdef BMPMAN_NDEBUG
- + be->data_size = 0;
- +#endif
- + be->signature = Bm_next_signature++;
- }
- -bitmap_lookup::~bitmap_lookup()
- +/**
- +* A special version of bm_free_data() that can be safely used in gr_*_texture
- +* to save system memory once textures have been transfered to API memory
- +* it doesn't restore the slot to a pristine state, it only releases the data
- +*
- +* NOTE: THIS SHOULD ONLY BE USED FROM bm_unload_fast()!!!
- +*/
- +static void bm_free_data_fast(int n)
- {
- - if ( Bitmap_data != NULL ) {
- - vm_free(Bitmap_data);
- + bitmap_entry *be;
- + bitmap *bmp;
- +
- + Assert((n >= 0) && (n < MAX_BITMAPS));
- +
- + be = &bm_bitmaps[n];
- + bmp = &be->bm;
- +
- + // If there isn't a bitmap in this structure, don't
- + // do anything but clear out the bitmap info
- + if (be->type == BM_TYPE_NONE)
- + return;
- +
- + // Don't free up memory for user defined bitmaps, since
- + // BmpMan isn't the one in charge of allocating/deallocing them.
- + if (be->type == BM_TYPE_USER) {
- +#ifdef BMPMAN_NDEBUG
- + if (be->data_size != 0)
- + bm_texture_ram -= be->data_size;
- +#endif
- + return;
- }
- -}
- -bool bitmap_lookup::valid()
- -{
- - return Bitmap_data != NULL;
- + // If this bitmap doesn't have any data to free, skip
- + // the freeing it part of this.
- + if (bmp->data == 0) {
- +#ifdef BMPMAN_NDEBUG
- + if (be->data_size != 0) {
- + bm_texture_ram -= be->data_size;
- + be->data_size = 0;
- + }
- +#endif
- + return;
- + }
- +
- + // Free up the data now!
- +#ifdef BMPMAN_NDEBUG
- + bm_texture_ram -= be->data_size;
- + be->data_size = 0;
- +#endif
- + vm_free((void *)bmp->data);
- + bmp->data = 0;
- }
- -float bitmap_lookup::map_texture_address(float address)
- +
- +void bm_clean_slot(int n)
- {
- - // assume we're just wrapping
- - return address - floorf(address);
- + bm_free_data(n);
- }
- -float bitmap_lookup::get_channel_red(float u, float v)
- +
- +void *bm_malloc(int n, int size)
- {
- - Assert( Bitmap_data != NULL );
- + Assert((n >= 0) && (n < MAX_BITMAPS));
- - CLAMP(u, 0.0, 1.0f);
- - CLAMP(v, 0.0, 1.0f);
- + if (size <= 0)
- + return NULL;
- - int x = fl2i(map_texture_address(u) * (Width-1));
- - int y = fl2i(map_texture_address(v) * (Height-1));
- +#ifdef BMPMAN_NDEBUG
- + Assert(bm_bitmaps[n].data_size == 0);
- + bm_bitmaps[n].data_size += size;
- + bm_texture_ram += size;
- +#endif
- - return Bitmap_data[(y*Width + x)*Num_channels];
- + return vm_malloc(size);
- }
- -float bitmap_lookup::get_channel_green(float u, float v)
- +/**
- +* Like bm_malloc but only keeps track of how much memory is getting used
- +*/
- +void bm_update_memory_used(int n, int size)
- {
- - Assert( Bitmap_data != NULL );
- -
- - CLAMP(u, 0.0, 1.0f);
- - CLAMP(v, 0.0, 1.0f);
- + Assert((n >= 0) && (n < MAX_BITMAPS));
- + Assert(size >= 0);
- - int x = fl2i(map_texture_address(u) * (Width-1));
- - int y = fl2i(map_texture_address(v) * (Height-1));
- +#ifdef BMPMAN_NDEBUG
- + Assert(bm_bitmaps[n].data_size == 0);
- + bm_bitmaps[n].data_size += size;
- + bm_texture_ram += size;
- +#endif
- +}
- - return Bitmap_data[(y*Width + x)*Num_channels + 1];
- +void bm_close()
- +{
- + int i;
- + if (bm_inited) {
- + for (i = 0; i<MAX_BITMAPS; i++) {
- + bm_free_data(i); // clears flags, bbp, data, etc
- + }
- + bm_inited = 0;
- + }
- }
- -float bitmap_lookup::get_channel_blue(float u, float v)
- +void bm_init()
- {
- - Assert( Bitmap_data != NULL );
- + int i;
- - int x = fl2i(map_texture_address(u) * (Width-1));
- - int y = fl2i(map_texture_address(v) * (Height-1));
- + mprintf(("Size of bitmap info = %d KB\n", sizeof(bm_bitmaps) / 1024));
- + mprintf(("Size of bitmap extra info = %d bytes\n", sizeof(bm_extra_info)));
- - return Bitmap_data[(y*Width + x)*Num_channels + 2];
- -}
- + if (!bm_inited) {
- + bm_inited = 1;
- + atexit(bm_close);
- + }
- -float bitmap_lookup::get_channel_alpha(float u, float v)
- -{
- - Assert( Bitmap_data != NULL );
- + for (i = 0; i<MAX_BITMAPS; i++) {
- + bm_bitmaps[i].filename[0] = '\0';
- + bm_bitmaps[i].type = BM_TYPE_NONE;
- + bm_bitmaps[i].comp_type = BM_TYPE_NONE;
- + bm_bitmaps[i].dir_type = CF_TYPE_ANY;
- + bm_bitmaps[i].info.user.data = NULL;
- + bm_bitmaps[i].mem_taken = 0;
- + bm_bitmaps[i].bm.data = 0;
- + bm_bitmaps[i].bm.palette = NULL;
- + bm_bitmaps[i].info.ani.eff.type = BM_TYPE_NONE;
- + bm_bitmaps[i].info.ani.eff.filename[0] = '\0';
- +#ifdef BMPMAN_NDEBUG
- + bm_bitmaps[i].data_size = 0;
- + bm_bitmaps[i].used_count = 0;
- + bm_bitmaps[i].used_last_frame = 0;
- + bm_bitmaps[i].used_this_frame = 0;
- +#endif
- + bm_bitmaps[i].load_count = 0;
- - int x = fl2i(map_texture_address(u) * (Width-1));
- - int y = fl2i(map_texture_address(v) * (Height-1));
- + gr_bm_init(i);
- - return Bitmap_data[(y*Width + x)*Num_channels + 3];
- + bm_free_data(i); // clears flags, bbp, data, etc
- + }
- }
- /**
- - * Converts the bitmap referenced by bmp to the type specified by flags
- - */
- -static void bm_convert_format(bitmap *bmp, ubyte flags);
- +* Returns number of bytes of bitmaps locked this frame
- +* @param ntotal number of bytes of bitmaps locked this frame
- +* @param nnew number of bytes of bitmaps locked this frame that weren't locked last frame
- +*/
- +void bm_get_frame_usage(int *ntotal, int *nnew)
- +{
- +#ifdef BMPMAN_NDEBUG
- + int i;
- -/**
- - * Frees a bitmap's data if it can
- - */
- -static void bm_free_data(int n, bool release = false);
- + *ntotal = 0;
- + *nnew = 0;
- -/**
- - * A special version of bm_free_data() that can be safely used in gr_*_texture
- - * to save system memory once textures have been transfered to API memory
- - * it doesn't restore the slot to a pristine state, it only releases the data
- - *
- - * @attention: THIS SHOULD ONLY BE USED FROM bm_unload_fast()!!!
- - */
- -static void bm_free_data_fast(int n);
- + for (i = 0; i<MAX_BITMAPS; i++) {
- + if ((bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].used_this_frame)) {
- + if (!bm_bitmaps[i].used_last_frame) {
- + *nnew += bm_bitmaps[i].mem_taken;
- + }
- + *ntotal += bm_bitmaps[i].mem_taken;
- + }
- + bm_bitmaps[i].used_last_frame = bm_bitmaps[i].used_this_frame;
- + bm_bitmaps[i].used_this_frame = 0;
- + }
- +#endif
- +}
- /**
- - * Given a raw filename and an extension set, try and find the bitmap
- - * that isn't already loaded and may exist somewhere on the disk
- - *
- - * @returns -1 if it could not be found,
- - * @returns index into ext_list[] if it was found as a file, fills img_cfg if available
- - */
- -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);
- +* Creates a bitmap that exists in RAM somewhere, instead
- +* of coming from a disk file.
- +*
- +* You pass in a pointer to a block of 32 (or 8)-bit-per-pixel data.
- +* Right now, the only bpp you can pass in is 32 or 8.
- +*
- +* On success, it returns the bitmap number.
- +*
- +* You cannot free that RAM until bm_release is called on that bitmap.
- +*/
- +int bm_create(int bpp, int w, int h, void *data, int flags)
- +{
- + if (bpp == 8) {
- + Assert(flags & BMP_AABITMAP);
- + }
- + else {
- + Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
- + }
- -/**
- - * Given a raw filename, try and find a bitmap that's already loaded
- - *
- - * @returns 0 if it could not be found,
- - * @returns 1 if it already exists, fills in handle
- - */
- -static int bm_load_sub_fast(const char *real_filename, int *handle, int dir_type = CF_TYPE_ANY, bool animated_type = false);
- -
- -/**
- - * Finds a block of... something
- - *
- - * @returns -1 if the block could not be found
- - * @returns the handle of the block ?
- - */
- -static int find_block_of(int n);
- -
- -// --------------------------------------------------------------------------------------------------------------------
- -// Macro-defined functions
- -
- -DCF(bm_frag, "Shows BmpMan fragmentation") {
- - if (dc_optional_string_either("help", "--help")) {
- - dc_printf("Displays a graphic showing the BmpMan fragmentation. Color key:\n");
- - dc_printf("\tGray : NONE\n");
- - dc_printf("\tRed : PCXn");
- - dc_printf("\tGreen : USER, TGA, PNG, DDS, other\n");
- - dc_printf("\tBlue : ANI, EFF\n\n");
- -
- - dc_printf("Once done reviewing the graphic, press any key to return to the console\n");
- - return;
- - }
- -
- - gr_clear();
- -
- - int x = 0, y = 0;
- - int xs = 2, ys = 2;
- - int w = 4, h = 4;
- -
- - for (int i = 0; i<MAX_BITMAPS; i++) {
- - switch (bm_bitmaps[i].type) {
- - case BM_TYPE_NONE:
- - gr_set_color(128, 128, 128);
- - break;
- - case BM_TYPE_PCX:
- - gr_set_color(255, 0, 0);
- - break;
- - case BM_TYPE_USER:
- - case BM_TYPE_TGA:
- - case BM_TYPE_PNG:
- - case BM_TYPE_DDS:
- - gr_set_color(0, 255, 0);
- - break;
- - case BM_TYPE_ANI:
- - case BM_TYPE_EFF:
- - gr_set_color(0, 0, 255);
- - break;
- - default:
- - gr_set_color(0, 255, 0);
- - break;
- - }
- -
- - gr_rect(x + xs, y + ys, w, h);
- - x += w + xs + xs;
- - if (x > 639) {
- - x = 0;
- - y += h + ys + ys;
- - }
- - }
- -
- - gr_flip();
- - key_getch();
- -}
- -
- -DCF(bmpman, "Shows/changes bitmap caching parameters and usage") {
- - if (dc_optional_string_either("help", "--help")) {
- - dc_printf("Usage: BmpMan [arg]\nWhere arg can be any of the following:\n");
- - dc_printf("\tflush Unloads all bitmaps.\n");
- - dc_printf("\tram [x] Sets max mem usage to x MB. (Set to 0 to have no limit.)\n");
- - dc_printf("\t? Displays status of Bitmap manager.\n");
- - return;
- - }
- -
- - if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
- - dc_printf("Total RAM usage: %d bytes\n", bm_texture_ram);
- -
- - if (Bm_max_ram > 1024 * 1024) {
- - dc_printf("\tMax RAM allowed: %.1f MB\n", i2fl(Bm_max_ram) / (1024.0f*1024.0f));
- - } else if (Bm_max_ram > 1024) {
- - dc_printf("\tMax RAM allowed: %.1f KB\n", i2fl(Bm_max_ram) / (1024.0f));
- - } else if (Bm_max_ram > 0) {
- - dc_printf("\tMax RAM allowed: %d bytes\n", Bm_max_ram);
- - } else {
- - dc_printf("\tNo RAM limit\n");
- - }
- - return;
- - }
- -
- -
- - if (dc_optional_string("flush")) {
- - dc_printf("Total RAM usage before flush: %d bytes\n", bm_texture_ram);
- - int i;
- - for (i = 0; i < MAX_BITMAPS; i++) {
- - if (bm_bitmaps[i].type != BM_TYPE_NONE) {
- - bm_free_data(i);
- - }
- - }
- - dc_printf("Total RAM after flush: %d bytes\n", bm_texture_ram);
- - } else if (dc_optional_string("ram")) {
- - dc_stuff_int(&Bm_max_ram);
- -
- - if (Bm_max_ram > 0) {
- - dc_printf("BmpMan limited to %i, MB's\n", Bm_max_ram);
- - Bm_max_ram *= 1024 * 1024;
- - } else if (Bm_max_ram == 0) {
- - dc_printf("!!BmpMan memory is unlimited!!\n");
- - } else {
- - dc_printf("Illegal value. Must be non-negative.");
- - }
- - } else {
- - dc_printf("<BmpMan> No argument given\n");
- - }
- -}
- -
- -DCF(bmpslots, "Writes bitmap slot info to fs2_open.log") {
- - if (dc_optional_string_either("help", "--help")) {
- - dc_printf("Usage: bmpslots\n");
- - dc_printf("\tWrites bitmap slot info to fs2_open.log\n");
- - return;
- - }
- - bm_print_bitmaps();
- -}
- -
- -// --------------------------------------------------------------------------------------------------------------------
- -// Definition of all functions, in alphabetical order
- -void bm_clean_slot(int n) {
- - bm_free_data(n);
- -}
- -
- -void bm_close() {
- - int i;
- - if (bm_inited) {
- - for (i = 0; i<MAX_BITMAPS; i++) {
- - bm_free_data(i); // clears flags, bbp, data, etc
- - }
- - bm_inited = 0;
- - }
- -}
- -
- -int bm_create(int bpp, int w, int h, void *data, int flags) {
- - if (bpp == 8) {
- - Assert(flags & BMP_AABITMAP);
- - } else {
- - Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
- - }
- -
- - if (!bm_inited) bm_init();
- + if (!bm_inited) bm_init();
- int n = -1;
- @@ -424,526 +405,482 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
- bm_bitmaps[n].load_count++;
- - bm_update_memory_used(n, (int)bm_bitmaps[n].mem_taken);
- + bm_update_memory_used(n, bm_bitmaps[n].mem_taken);
- gr_bm_create(n);
- return bm_bitmaps[n].handle;
- }
- -void bm_convert_format(bitmap *bmp, ubyte flags) {
- - int idx;
- +/**
- +* Given a raw filename and an extension set, try and find the bitmap
- +* that isn't already loaded and may exist somewhere on the disk
- +*
- +* @return -1 if it could not be found index into ext_list[] if it was found as a file, fills img_cfg if available
- +*/
- +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)
- +{
- + char full_path[MAX_PATH];
- + int size = 0, offset = 0;
- + int rval = -1;
- - // no transparency for 24 bpp images
- - if (!(flags & BMP_AABITMAP) && (bmp->bpp == 24))
- - return;
- + rval = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, sizeof(full_path) - 1, full_path, &size, &offset, 0);
- - if (Is_standalone) {
- - Assert(bmp->bpp == 8);
- - return;
- - } else {
- - if (flags & BMP_AABITMAP)
- - Assert(bmp->bpp == 8);
- - else
- - Assert((bmp->bpp == 16) || (bmp->bpp == 32));
- - }
- + // could not be found, or is invalid for some reason
- + if ((rval < 0) || (rval >= num_ext))
- + return -1;
- - // maybe swizzle to be an xparent texture
- - if (!(bmp->flags & BMP_TEX_XPARENT) && (flags & BMP_TEX_XPARENT)) {
- - for (idx = 0; idx<bmp->w*bmp->h; idx++) {
- - // if the pixel is transparent
- - if (((ushort*)bmp->data)[idx] == Gr_t_green.mask) {
- - ((ushort*)bmp->data)[idx] = 0;
- - }
- - }
- + CFILE *test = cfopen_special(full_path, "rb", size, offset, dir_type);
- - bmp->flags |= BMP_TEX_XPARENT;
- + if (test != NULL) {
- + if (img_cfp != NULL)
- + *img_cfp = test;
- +
- + return rval;
- }
- +
- + // umm, that's not good...
- + return -1;
- }
- -void bm_free_data(int n, bool release)
- +/**
- +* Given a raw filename, try and find a bitmap that's already loaded
- +* @return 0 if it could not be found, 1 if it already exists, fills in handle
- +*/
- +int bm_load_sub_fast(const char *real_filename, int *handle, int dir_type = CF_TYPE_ANY, bool animated_type = false)
- {
- - bitmap_entry *be;
- - bitmap *bmp;
- + if (Bm_ignore_duplicates)
- + return 0;
- - Assert( (n >= 0) && (n < MAX_BITMAPS) );
- + int i;
- - be = &bm_bitmaps[n];
- - bmp = &be->bm;
- + for (i = 0; i < MAX_BITMAPS; i++) {
- + if (bm_bitmaps[i].type == BM_TYPE_NONE)
- + continue;
- - gr_bm_free_data(n, release);
- + if (bm_bitmaps[i].dir_type != dir_type)
- + continue;
- - // If there isn't a bitmap in this structure, don't
- - // do anything but clear out the bitmap info
- - if (be->type==BM_TYPE_NONE)
- - goto SkipFree;
- + bool animated = ((bm_bitmaps[i].type == BM_TYPE_EFF) || (bm_bitmaps[i].type == BM_TYPE_ANI));
- - // Don't free up memory for user defined bitmaps, since
- - // BmpMan isn't the one in charge of allocating/deallocing them.
- - if (be->type==BM_TYPE_USER) {
- -#ifdef BMPMAN_NDEBUG
- - if ( be->data_size != 0 )
- - bm_texture_ram -= be->data_size;
- -#endif
- - goto SkipFree;
- - }
- + if (animated_type && !animated)
- + continue;
- + else if (!animated_type && animated)
- + continue;
- - // If this bitmap doesn't have any data to free, skip
- - // the freeing it part of this.
- - if (bmp->data == 0) {
- -#ifdef BMPMAN_NDEBUG
- - if ( be->data_size != 0 )
- - bm_texture_ram -= be->data_size;
- -#endif
- - goto SkipFree;
- + if (!strextcmp(real_filename, bm_bitmaps[i].filename)) {
- + nprintf(("BmpFastLoad", "Found bitmap %s -- number %d\n", bm_bitmaps[i].filename, i));
- + bm_bitmaps[i].load_count++;
- + *handle = bm_bitmaps[i].handle;
- + return 1;
- + }
- }
- - // Free up the data now!
- -#ifdef BMPMAN_NDEBUG
- - bm_texture_ram -= be->data_size;
- -#endif
- - vm_free((void *)bmp->data);
- -
- - // reset the load_count to at least 1, don't do this in SkipFree though
- - // since the real count ends up wrong
- - be->load_count = 1;
- -
- -SkipFree:
- -
- - // Clear out & reset the bitmap data structure
- - bmp->flags = 0;
- - bmp->bpp = 0;
- - bmp->data = 0;
- - bmp->palette = NULL;
- -#ifdef BMPMAN_NDEBUG
- - be->data_size = 0;
- -#endif
- - be->signature = Bm_next_signature++;
- + // not found to be loaded already
- + return 0;
- }
- -void bm_free_data_fast(int n)
- +/**
- +* Loads a bitmap so we can draw with it later.
- +* Function doesn't actually load the data, only width, height, and possibly flags.
- +*
- +* @return A negative number if it couldn't load the bitmap.
- +* @return On success, it returns the bitmap number.
- +*/
- +int bm_load(const char *real_filename)
- {
- - bitmap_entry *be;
- - bitmap *bmp;
- + int i, id = -1, free_slot = -1;
- + int w, h, bpp = 8;
- + int rc = 0;
- + int bm_size = 0, mm_lvl = 0;
- + char filename[MAX_FILENAME_LEN];
- + ubyte type = BM_TYPE_NONE;
- + ubyte c_type = BM_TYPE_NONE;
- + CFILE *img_cfp = NULL;
- + int handle = -1;
- - Assert( (n >= 0) && (n < MAX_BITMAPS) );
- + if (!bm_inited)
- + bm_init();
- - be = &bm_bitmaps[n];
- - bmp = &be->bm;
- + // if no file was passed then get out now
- + if ((real_filename == NULL) || (strlen(real_filename) <= 0))
- + return -1;
- - // If there isn't a bitmap in this structure, don't
- - // do anything but clear out the bitmap info
- - if (be->type == BM_TYPE_NONE)
- - return;
- + // make sure no one passed an extension
- + memset(filename, 0, MAX_FILENAME_LEN);
- + strncpy(filename, real_filename, MAX_FILENAME_LEN - 1);
- + char *p = strrchr(filename, '.');
- + if (p) {
- + mprintf(("Someone passed an extension to bm_load for file '%s'\n", real_filename));
- + *p = 0;
- + }
- - // Don't free up memory for user defined bitmaps, since
- - // BmpMan isn't the one in charge of allocating/deallocing them.
- - if (be->type == BM_TYPE_USER) {
- -#ifdef BMPMAN_NDEBUG
- - if ( be->data_size != 0 )
- - bm_texture_ram -= be->data_size;
- -#endif
- - return;
- + // If we are standalone server keep replacing the 'right_bracket' (right side help bracket) as the filename
- + // should keep the game happy while loading only single pcx file which the needs to be present in any case
- + if (Is_standalone) {
- + char standalone_filename[MAX_FILENAME_LEN] = "right_bracket";
- + strcpy_s(filename, standalone_filename);
- }
- - // If this bitmap doesn't have any data to free, skip
- - // the freeing it part of this.
- - if (bmp->data == 0) {
- -#ifdef BMPMAN_NDEBUG
- - if ( be->data_size != 0 ) {
- - bm_texture_ram -= be->data_size;
- - be->data_size = 0;
- - }
- -#endif
- - return;
- + // safety catch for strcat...
- + // MAX_FILENAME_LEN-5 == '.' plus 3 letter ext plus NULL terminator
- + if (strlen(filename) > MAX_FILENAME_LEN - 5) {
- + 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);
- + return -1;
- }
- - // Free up the data now!
- -#ifdef BMPMAN_NDEBUG
- - bm_texture_ram -= be->data_size;
- - be->data_size = 0;
- -#endif
- - vm_free((void *)bmp->data);
- - bmp->data = 0;
- -}
- + // Lets find out what type it is
- + {
- + const int NUM_TYPES = 5;
- + const ubyte type_list[NUM_TYPES] = { BM_TYPE_DDS, BM_TYPE_TGA, BM_TYPE_PNG, BM_TYPE_JPG, BM_TYPE_PCX };
- + const char *ext_list[NUM_TYPES] = { ".dds", ".tga", ".png", ".jpg", ".pcx" };
- -int bm_get_cache_slot(int bitmap_id, int separate_ani_frames) {
- - int n = bitmap_id % MAX_BITMAPS;
- + // see if it's already loaded (checks for any type with filename)
- + if (bm_load_sub_fast(filename, &handle))
- + return handle;
- - Assert(n >= 0);
- - Assert(bm_bitmaps[n].handle == bitmap_id); // INVALID BITMAP HANDLE
- + // if we are still here then we need to fall back to a file-based search
- + int rval = bm_load_sub_slow(filename, NUM_TYPES, ext_list, &img_cfp);
- - bitmap_entry *be = &bm_bitmaps[n];
- + if (rval < 0)
- + return -1;
- - if ((!separate_ani_frames) && ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF))) {
- - return be->info.ani.first_frame;
- + strcat_s(filename, ext_list[rval]);
- + type = type_list[rval];
- }
- - return n;
- -
- -}
- -
- -void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) {
- - int bit_32 = 0;
- -
- - if ((gr_screen.bits_per_pixel == 32) && (Gr_current_red == &Gr_red)) {
- - bit_32 = 1;
- - }
- + Assert(type != BM_TYPE_NONE);
- - if (r != NULL) {
- - if (bit_32) {
- - *r = ubyte(((*((unsigned int*)pixel) & Gr_current_red->mask) >> Gr_current_red->shift)*Gr_current_red->scale);
- - } else {
- - *r = ubyte(((((unsigned short*)pixel)[0] & Gr_current_red->mask) >> Gr_current_red->shift)*Gr_current_red->scale);
- + // Find an open slot
- + for (i = 0; i < MAX_BITMAPS; i++) {
- + if (bm_bitmaps[i].type == BM_TYPE_NONE) {
- + free_slot = i;
- + break;
- }
- }
- - if (g != NULL) {
- - if (bit_32) {
- - *g = ubyte(((*((unsigned int*)pixel) & Gr_current_green->mask) >> Gr_current_green->shift)*Gr_current_green->scale);
- - } else {
- - *g = ubyte(((((unsigned short*)pixel)[0] & Gr_current_green->mask) >> Gr_current_green->shift)*Gr_current_green->scale);
- - }
- + if (free_slot < 0) {
- + Assertion(free_slot < 0, "Could not find free BMPMAN slot for bitmap: %s", real_filename);
- + goto Done;
- }
- - if (b != NULL) {
- - if (bit_32) {
- - *b = ubyte(((*((unsigned int*)pixel) & Gr_current_blue->mask) >> Gr_current_blue->shift)*Gr_current_blue->scale);
- - } else {
- - *b = ubyte(((((unsigned short*)pixel)[0] & Gr_current_blue->mask) >> Gr_current_blue->shift)*Gr_current_blue->scale);
- - }
- - }
- + rc = gr_bm_load(type, free_slot, filename, img_cfp, &w, &h, &bpp, &c_type, &mm_lvl, &bm_size);
- - // get the alpha value
- - if (a != NULL) {
- - *a = 1;
- + if (rc != 0)
- + goto Done;
- - Assert(!bit_32);
- - if (!(((unsigned short*)pixel)[0] & 0x8000)) {
- - *a = 0;
- - }
- - }
- -}
- + if ((bm_size <= 0) && (w) && (h) && (bpp))
- + bm_size = (w * h * (bpp >> 3));
- -const char *bm_get_filename(int handle) {
- - int n;
- - n = handle % MAX_BITMAPS;
- - Assert(bm_bitmaps[n].handle == handle); // INVALID BITMAP HANDLE
- - return bm_bitmaps[n].filename;
- -}
- + handle = bm_get_next_handle() * MAX_BITMAPS + free_slot;
- -void bm_get_filename(int bitmapnum, char *filename) {
- - if (!bm_is_valid(bitmapnum)) {
- - strcpy(filename, "");
- - return;
- - }
- + // ensure fields are cleared out from previous bitmap
- + memset(&bm_bitmaps[free_slot], 0, sizeof(bitmap_entry));
- - int n = bitmapnum % MAX_BITMAPS;
- + // Mark the slot as filled, because cf_read might load a new bitmap
- + // into this slot.
- + strncpy(bm_bitmaps[free_slot].filename, filename, MAX_FILENAME_LEN - 1);
- + bm_bitmaps[free_slot].id = id;
- + bm_bitmaps[free_slot].type = type;
- + bm_bitmaps[free_slot].comp_type = c_type;
- + bm_bitmaps[free_slot].signature = Bm_next_signature++;
- + bm_bitmaps[free_slot].bm.w = (short)w;
- + bm_bitmaps[free_slot].bm.rowsize = (short)w;
- + bm_bitmaps[free_slot].bm.h = (short)h;
- + bm_bitmaps[free_slot].bm.bpp = 0;
- + bm_bitmaps[free_slot].bm.true_bpp = (ubyte)bpp;
- + bm_bitmaps[free_slot].bm.flags = 0;
- + bm_bitmaps[free_slot].bm.data = 0;
- + bm_bitmaps[free_slot].bm.palette = NULL;
- + bm_bitmaps[free_slot].num_mipmaps = mm_lvl;
- + bm_bitmaps[free_slot].mem_taken = bm_size;
- + bm_bitmaps[free_slot].dir_type = CF_TYPE_ANY;
- + bm_bitmaps[free_slot].palette_checksum = 0;
- + bm_bitmaps[free_slot].handle = handle;
- + bm_bitmaps[free_slot].last_used = -1;
- - Assert(n >= 0);
- + bm_bitmaps[free_slot].load_count++;
- +Done:
- + if (img_cfp != NULL)
- + cfclose(img_cfp);
- - // return filename
- - strcpy(filename, bm_bitmaps[n].filename);
- + return handle;
- }
- -void bm_get_frame_usage(int *ntotal, int *nnew) {
- -#ifdef BMPMAN_NDEBUG
- - int i;
- +/**
- +* Same as bm_load above, just with an SCP_string
- +*/
- +int bm_load(const SCP_string& filename)
- +{
- + return bm_load(filename.c_str());
- +}
- - *ntotal = 0;
- - *nnew = 0;
- +/**
- +* Special load function. Basically allows you to load a bitmap which already exists (by filename).
- +*
- +* This is useful because in some cases we need to have a bitmap which is locked in screen format
- +* _and_ texture format, such as pilot pics and squad logos
- +*/
- +int bm_load_duplicate(const char *filename)
- +{
- + int ret;
- - for (i = 0; i<MAX_BITMAPS; i++) {
- - if ((bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].used_this_frame)) {
- - if (!bm_bitmaps[i].used_last_frame) {
- - *nnew += (int)bm_bitmaps[i].mem_taken;
- - }
- - *ntotal += (int)bm_bitmaps[i].mem_taken;
- - }
- - bm_bitmaps[i].used_last_frame = bm_bitmaps[i].used_this_frame;
- - bm_bitmaps[i].used_this_frame = 0;
- - }
- -#endif
- + // ignore duplicates
- + Bm_ignore_duplicates = 1;
- +
- + // load
- + ret = bm_load(filename);
- +
- + // back to normal
- + Bm_ignore_duplicates = 0;
- +
- + return ret;
- }
- -int bm_get_info(int handle, int *w, int * h, ubyte * flags, int *nframes, int *fps) {
- - bitmap * bmp;
- +/**
- +* This function is used to reload a different bitmap into an existing slot.
- +* This should only be used if you are certain the new picture has the same type, dimensions etc.
- +*
- +* @return negative if the given handle doesn't exist, the filename was empty or the slot is still locked
- +* @return the bitmap_handle on success
- +*/
- +int bm_reload(int bitmap_handle, const char* filename)
- +{
- + if (!bm_inited)
- + bm_init();
- - if (!bm_inited) return -1;
- + // if no file was passed then get out now
- + if ((filename == NULL) || (strlen(filename) <= 0))
- + return -1;
- - int bitmapnum = handle % MAX_BITMAPS;
- + int bitmapnum = bitmap_handle % MAX_BITMAPS;
- -#ifndef NDEBUG
- - if (bm_bitmaps[bitmapnum].handle != handle) {
- - mprintf(("bm_get_info - %s: bm_bitmaps[%d].handle = %d, handle = %d\n", bm_bitmaps[bitmapnum].filename, bitmapnum, bm_bitmaps[bitmapnum].handle, handle));
- + if (bm_bitmaps[bitmapnum].type == BM_TYPE_NONE)
- + return -1;
- +
- + if (bm_bitmaps[bitmapnum].ref_count)
- + {
- + 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));
- + return -1;
- }
- -#endif
- - 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!
- + strcpy_s(bm_bitmaps[bitmapnum].filename, filename);
- + return bitmap_handle;
- +}
- - if ((bm_bitmaps[bitmapnum].type == BM_TYPE_NONE) || (bm_bitmaps[bitmapnum].handle != handle)) {
- - if (w) *w = 0;
- - if (h) *h = 0;
- - if (flags) *flags = 0;
- - if (nframes) *nframes = 0;
- - if (fps) *fps = 0;
- - return -1;
- +DCF(bm_frag, "Shows BmpMan fragmentation")
- +{
- + if (dc_optional_string_either("help", "--help")) {
- + dc_printf("Displays a graphic showing the BmpMan fragmentation. Color key:\n");
- + dc_printf("\tGray : NONE\n");
- + dc_printf("\tRed : PCXn");
- + dc_printf("\tGreen : USER, TGA, PNG, DDS\n");
- + dc_printf("\tBlue : ANI, EFF\n\n");
- +
- + dc_printf("Once done reviewing the graphic, press any key to return to the console\n");
- + return;
- }
- - bmp = &(bm_bitmaps[bitmapnum].bm);
- + gr_clear();
- - if (w) *w = bmp->w;
- - if (h) *h = bmp->h;
- - if (flags) *flags = bmp->flags;
- + int x = 0, y = 0;
- + int xs = 2, ys = 2;
- + int w = 4, h = 4;
- - if ((bm_bitmaps[bitmapnum].type == BM_TYPE_ANI) || (bm_bitmaps[bitmapnum].type == BM_TYPE_EFF)) {
- - if (nframes) {
- - *nframes = bm_bitmaps[bitmapnum].info.ani.num_frames;
- - }
- - if (fps) {
- - *fps = bm_bitmaps[bitmapnum].info.ani.fps;
- + for (int i = 0; i<MAX_BITMAPS; i++) {
- + switch (bm_bitmaps[i].type) {
- + case BM_TYPE_NONE:
- + gr_set_color(128, 128, 128);
- + break;
- + case BM_TYPE_PCX:
- + gr_set_color(255, 0, 0);
- + break;
- + case BM_TYPE_USER:
- + case BM_TYPE_TGA:
- + case BM_TYPE_PNG:
- + case BM_TYPE_DDS:
- + gr_set_color(0, 255, 0);
- + break;
- + case BM_TYPE_ANI:
- + case BM_TYPE_EFF:
- + gr_set_color(0, 0, 255);
- + break;
- }
- - return bm_bitmaps[bm_bitmaps[bitmapnum].info.ani.first_frame].handle;
- - } else {
- - if (nframes) {
- - *nframes = 1;
- - }
- - if (fps) {
- - *fps = 0;
- + gr_rect(x + xs, y + ys, w, h);
- + x += w + xs + xs;
- + if (x > 639) {
- + x = 0;
- + y += h + ys + ys;
- }
- -
- - return handle;
- }
- +
- + gr_flip();
- + key_getch();
- }
- -int bm_get_next_handle() {
- - //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;
- - //as bitmaps get allocated and released, bm_next_handle could get there far more often than you'd think.
- - //The check introduced below is intended to replace this behaviour with one that ensures we won't be seeing handle collisions
- - //for a very long time.
- -
- - bm_next_handle++;
- +static int find_block_of(int n)
- +{
- + int i, cnt = 0, nstart = 0;
- - //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[]),
- - //this check is necessary to ensure we don't start giving out negative handles all of a sudden.
- - if ((bm_next_handle + 1) > INT_MAX / MAX_BITMAPS) {
- - bm_next_handle = 1;
- - mprintf(("BMPMAN: bitmap handles wrapped back to 1\n"));
- + if (n < 1) {
- + Int3();
- + return -1;
- }
- - return bm_next_handle;
- -}
- -
- -int bm_get_num_mipmaps(int num) {
- - int n = num % MAX_BITMAPS;
- -
- - Assert(n >= 0);
- - Assert(num == bm_bitmaps[n].handle);
- -
- - if (bm_bitmaps[n].num_mipmaps == 0)
- - return 1;
- -
- - return bm_bitmaps[n].num_mipmaps;
- -}
- -
- -void bm_get_palette(int handle, ubyte *pal, char *name) {
- - char *filename;
- - int w, h;
- -
- - int n = handle % MAX_BITMAPS;
- - Assert(bm_bitmaps[n].handle == handle); // INVALID BITMAP HANDLE
- -
- - filename = bm_bitmaps[n].filename;
- + for (i = 0; i < MAX_BITMAPS; i++) {
- + if (bm_bitmaps[i].type == BM_TYPE_NONE) {
- + if (cnt == 0)
- + nstart = i;
- - if (name) {
- - strcpy(name, filename);
- - }
- + cnt++;
- + }
- + else {
- + cnt = 0;
- + }
- - int pcx_error = pcx_read_header(filename, NULL, &w, &h, NULL, pal);
- - if (pcx_error != PCX_ERROR_NONE) {
- - // Error(LOCATION, "Couldn't open '%s'\n", filename );
- + if (cnt == n)
- + return nstart;
- }
- -}
- -
- -uint bm_get_signature(int handle) {
- - if (!bm_inited) bm_init();
- -
- - int bitmapnum = handle % MAX_BITMAPS;
- - 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!
- -
- - return bm_bitmaps[bitmapnum].signature;
- -}
- -size_t bm_get_size(int handle) {
- - int n = handle % MAX_BITMAPS;
- -
- - Assert(n >= 0);
- - Assert(handle == bm_bitmaps[n].handle);
- -
- - return bm_bitmaps[n].mem_taken;
- + return -1;
- }
- -int bm_get_tcache_type(int num) {
- - if (bm_is_compressed(num))
- - return TCACHE_TYPE_COMPRESSED;
- -
- - return TCACHE_TYPE_NORMAL;
- -}
- +int bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, ubyte *type)
- +{
- + int frames = 0, fps = 30, keyframe = 0, rval;
- + char ext[8];
- + ubyte c_type = BM_TYPE_NONE;
- + char file_text[1024];
- + char file_text_raw[1024];
- -BM_TYPE bm_get_type(int handle) {
- - if (!bm_inited) bm_init();
- + memset(ext, 0, sizeof(ext));
- + memset(file_text, 0, sizeof(file_text));
- + memset(file_text_raw, 0, sizeof(file_text_raw));
- - int bitmapnum = handle % MAX_BITMAPS;
- - 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!
- + // pause anything that may happen to be parsing right now
- + pause_parse();
- - return bm_bitmaps[bitmapnum].type;
- -}
- + if ((rval = setjmp(parse_abort)) != 0) {
- + mprintf(("BMPMAN: Unable to parse '%s'! Error code = %i.\n", filename, rval));
- + unpause_parse();
- + return -1;
- + }
- -bool bm_has_alpha_channel(int handle) {
- - int n = handle % MAX_BITMAPS;
- + // now start parsing the EFF
- + read_file_text(filename, dir_type, file_text, file_text_raw);
- + reset_parse(file_text);
- - Assert(n >= 0);
- - Assert(handle == bm_bitmaps[n].handle);
- + required_string("$Type:");
- + stuff_string(ext, F_NAME, sizeof(ext));
- - // assume that PCX never has a real alpha channel (it may be 32-bit, but without any alpha)
- - if (bm_bitmaps[n].type == BM_TYPE_PCX)
- - return 0;
- + required_string("$Frames:");
- + stuff_int(&frames);
- - return (bm_bitmaps[n].bm.true_bpp == 32);
- -}
- + if (optional_string("$FPS:"))
- + stuff_int(&fps);
- -void bm_init() {
- - int i;
- + if (optional_string("$Keyframe:"))
- + stuff_int(&keyframe);
- - mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", sizeof(bm_bitmaps) / 1024));
- - mprintf(("Size of bitmap extra info = " SIZE_T_ARG " bytes\n", sizeof(bm_extra_info)));
- + // done with EFF so unpause parsing so whatever can continue
- + unpause_parse();
- - if (!bm_inited) {
- - bm_inited = 1;
- - atexit(bm_close);
- + if (!stricmp(NOX("dds"), ext)) {
- + c_type = BM_TYPE_DDS;
- }
- -
- - for (i = 0; i<MAX_BITMAPS; i++) {
- - bm_bitmaps[i].filename[0] = '\0';
- - bm_bitmaps[i].type = BM_TYPE_NONE;
- - bm_bitmaps[i].comp_type = BM_TYPE_NONE;
- - bm_bitmaps[i].dir_type = CF_TYPE_ANY;
- - bm_bitmaps[i].info.user.data = NULL;
- - bm_bitmaps[i].mem_taken = 0;
- - bm_bitmaps[i].bm.data = 0;
- - bm_bitmaps[i].bm.palette = NULL;
- - bm_bitmaps[i].info.ani.eff.type = BM_TYPE_NONE;
- - bm_bitmaps[i].info.ani.eff.filename[0] = '\0';
- -#ifdef BMPMAN_NDEBUG
- - bm_bitmaps[i].data_size = 0;
- - bm_bitmaps[i].used_count = 0;
- - bm_bitmaps[i].used_last_frame = 0;
- - bm_bitmaps[i].used_this_frame = 0;
- -#endif
- - bm_bitmaps[i].load_count = 0;
- -
- - gr_bm_init(i);
- -
- - bm_free_data(i); // clears flags, bbp, data, etc
- + else if (!stricmp(NOX("tga"), ext)) {
- + c_type = BM_TYPE_TGA;
- }
- -}
- -
- -int bm_is_compressed(int num) {
- - int n = num % MAX_BITMAPS;
- - BM_TYPE type = BM_TYPE_NONE;
- -
- - //duh
- - if (!Use_compressed_textures)
- - return 0;
- -
- - Assert(n >= 0);
- - Assert(num == bm_bitmaps[n].handle);
- -
- - type = bm_bitmaps[n].comp_type;
- -
- - switch (type) {
- - case BM_TYPE_NONE:
- - case BM_TYPE_DDS:
- - return 0;
- -
- - case BM_TYPE_DXT1:
- - return DDS_DXT1;
- -
- - case BM_TYPE_DXT3:
- - return DDS_DXT3;
- -
- - case BM_TYPE_DXT5:
- - return DDS_DXT5;
- -
- - case BM_TYPE_CUBEMAP_DXT1:
- - return DDS_CUBEMAP_DXT1;
- -
- - case BM_TYPE_CUBEMAP_DXT3:
- - return DDS_CUBEMAP_DXT3;
- -
- - case BM_TYPE_CUBEMAP_DXT5:
- - return DDS_CUBEMAP_DXT5;
- -
- - default:
- - return 0;
- + else if (!stricmp(NOX("png"), ext)) {
- + c_type = BM_TYPE_PNG;
- + }
- + else if (!stricmp(NOX("jpg"), ext)) {
- + c_type = BM_TYPE_JPG;
- + }
- + else if (!stricmp(NOX("pcx"), ext)) {
- + c_type = BM_TYPE_PCX;
- + }
- + else {
- + mprintf(("BMPMAN: Unknown file type in EFF parse!\n"));
- + return -1;
- }
- -}
- -int bm_is_render_target(int bitmap_id) {
- - int n = bitmap_id % MAX_BITMAPS;
- + // did we do anything?
- + if (c_type == BM_TYPE_NONE || frames == 0) {
- + mprintf(("BMPMAN: EFF parse ERROR!\n"));
- + return -1;
- + }
- - Assert(n >= 0);
- - Assert(bitmap_id == bm_bitmaps[n].handle);
- + if (type)
- + *type = c_type;
- - if (!((bm_bitmaps[n].type == BM_TYPE_RENDER_TARGET_STATIC) || (bm_bitmaps[n].type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
- - return 0;
- - }
- + if (nframes)
- + *nframes = frames;
- - return bm_bitmaps[n].type;
- -}
- + if (nfps)
- + *nfps = fps;
- -int bm_is_valid(int handle) {
- - // Ensure that certain known false or out of range handles are quickly returned as invalid,
- - // prior to utilising the handle in a way which leads to memory access outside bm_bitmaps[]
- - if (!bm_inited) return 0;
- - if (handle < 0) return 0;
- + if (key)
- + *key = keyframe;
- - return (bm_bitmaps[handle % MAX_BITMAPS].handle == handle);
- + return 0;
- }
- -int bm_load(const char *real_filename) {
- - int i, free_slot = -1;
- - int w, h, bpp = 8;
- - int rc = 0;
- - int bm_size = 0, mm_lvl = 0;
- +/**
- +* Load animation
- +*
- +* @param real_filename filename of animation
- +* @param nframes OUTPUT parameter: number of frames in the animation
- +* @param fps OUTPUT/OPTIONAL parameter: intended fps for the animation
- +* @param keyframe Keyframe number
- +* @param can_drop_frames Toggle to allow dropped frames
- +* @param dir_type Directory type
- +*
- +* @returns Bitmap number of first frame in the animation
- +*/
- +int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
- +{
- + int i, n;
- + anim the_anim;
- + CFILE *img_cfp = NULL;
- char filename[MAX_FILENAME_LEN];
- - BM_TYPE type = BM_TYPE_NONE;
- - BM_TYPE c_type = BM_TYPE_NONE;
- - CFILE *img_cfp = NULL;
- - int handle = -1;
- + int reduced = 0;
- + int anim_fps = 0, anim_frames = 0, key = 0;
- + int anim_width = 0, anim_height = 0;
- + ubyte type = BM_TYPE_NONE, eff_type = BM_TYPE_NONE, c_type = BM_TYPE_NONE;
- + int bpp = 0, mm_lvl = 0, img_size = 0;
- + char clean_name[MAX_FILENAME_LEN];
- + const int NUM_TYPES = 2;
- + const ubyte type_list[NUM_TYPES] = { BM_TYPE_EFF, BM_TYPE_ANI };
- + const char *ext_list[NUM_TYPES] = { ".eff", ".ani" };
- if (!bm_inited)
- bm_init();
- - // if no file was passed then get out now
- - if ((real_filename == NULL) || (strlen(real_filename) <= 0))
- - return -1;
- + // set defaults for frame count and fps before going any further
- + if (nframes)
- + *nframes = 0;
- +
- + if (fps)
- + *fps = 0;
- +
- + if (keyframe)
- + *keyframe = 0;
- - // make sure no one passed an extension
- memset(filename, 0, MAX_FILENAME_LEN);
- strncpy(filename, real_filename, MAX_FILENAME_LEN - 1);
- - char *p = strrchr(filename, '.');
- + char *p = strchr(filename, '.');
- if (p) {
- - mprintf(("Someone passed an extension to bm_load for file '%s'\n", real_filename));
- + mprintf(("Someone passed an extension to bm_load_animation for file '%s'\n", real_filename));
- *p = 0;
- }
- - // If we are standalone server keep replacing the 'right_bracket' (right side help bracket) as the filename
- - // should keep the game happy while loading only single pcx file which the needs to be present in any case
- + // If we are standalone server keep replacing the 'cursorweb' (mouse cursor) as the filename
- + // should keep the game happy while loading only single ani file which the needs to be present in any case
- if (Is_standalone) {
- - char standalone_filename[MAX_FILENAME_LEN] = "right_bracket";
- + char standalone_filename[MAX_FILENAME_LEN] = "cursorweb";
- strcpy_s(filename, standalone_filename);
- }
- @@ -954,224 +891,20 @@ int bm_load(const char *real_filename) {
- return -1;
- }
- + // used later if EFF type
- + strcpy_s(clean_name, filename);
- +
- // Lets find out what type it is
- {
- - // see if it's already loaded (checks for any type with filename)
- - if (bm_load_sub_fast(filename, &handle))
- - return handle;
- + int handle = -1;
- - // if we are still here then we need to fall back to a file-based search
- - int rval = bm_load_sub_slow(filename, BM_NUM_TYPES, bm_ext_list, &img_cfp);
- + // do a search for any previously loaded files (looks at filename only)
- + if (bm_load_sub_fast(filename, &handle, dir_type, true)) {
- + n = handle % MAX_BITMAPS;
- + Assert(bm_bitmaps[n].handle == handle);
- - if (rval < 0)
- - return -1;
- -
- - strcat_s(filename, bm_ext_list[rval]);
- - type = bm_type_list[rval];
- - }
- -
- - Assert(type != BM_TYPE_NONE);
- -
- - // Find an open slot
- - for (i = 0; i < MAX_BITMAPS; i++) {
- - if (bm_bitmaps[i].type == BM_TYPE_NONE) {
- - free_slot = i;
- - break;
- - }
- - }
- -
- - if (free_slot < 0) {
- - Assertion(free_slot < 0, "Could not find free BMPMAN slot for bitmap: %s", real_filename);
- - goto Done;
- - }
- -
- - rc = gr_bm_load(type, free_slot, filename, img_cfp, &w, &h, &bpp, &c_type, &mm_lvl, &bm_size);
- -
- - if (rc != 0)
- - goto Done;
- -
- - if ((bm_size <= 0) && (w) && (h) && (bpp))
- - bm_size = (w * h * (bpp >> 3));
- -
- -
- - handle = bm_get_next_handle() * MAX_BITMAPS + free_slot;
- -
- - // ensure fields are cleared out from previous bitmap
- - memset(&bm_bitmaps[free_slot], 0, sizeof(bitmap_entry));
- -
- - // Mark the slot as filled, because cf_read might load a new bitmap
- - // into this slot.
- - strncpy(bm_bitmaps[free_slot].filename, filename, MAX_FILENAME_LEN - 1);
- - bm_bitmaps[free_slot].type = type;
- - bm_bitmaps[free_slot].comp_type = c_type;
- - bm_bitmaps[free_slot].signature = Bm_next_signature++;
- - bm_bitmaps[free_slot].bm.w = (short)w;
- - bm_bitmaps[free_slot].bm.rowsize = (short)w;
- - bm_bitmaps[free_slot].bm.h = (short)h;
- - bm_bitmaps[free_slot].bm.bpp = 0;
- - bm_bitmaps[free_slot].bm.true_bpp = (ubyte)bpp;
- - bm_bitmaps[free_slot].bm.flags = 0;
- - bm_bitmaps[free_slot].bm.data = 0;
- - bm_bitmaps[free_slot].bm.palette = NULL;
- - bm_bitmaps[free_slot].num_mipmaps = mm_lvl;
- - bm_bitmaps[free_slot].mem_taken = (size_t)bm_size;
- - bm_bitmaps[free_slot].dir_type = CF_TYPE_ANY;
- - bm_bitmaps[free_slot].palette_checksum = 0;
- - bm_bitmaps[free_slot].handle = handle;
- - bm_bitmaps[free_slot].last_used = -1;
- -
- - bm_bitmaps[free_slot].load_count++;
- -
- -Done:
- - if (img_cfp != NULL)
- - cfclose(img_cfp);
- -
- - return handle;
- -}
- -
- -int bm_load(const SCP_string& filename) {
- - return bm_load(filename.c_str());
- -}
- -
- -bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type) {
- - int frames = 0, fps = 30, keyframe = 0;
- - char ext[8];
- - BM_TYPE c_type = BM_TYPE_NONE;
- - char file_text[1024];
- - char file_text_raw[1024];
- -
- - memset(ext, 0, sizeof(ext));
- - memset(file_text, 0, sizeof(file_text));
- - memset(file_text_raw, 0, sizeof(file_text_raw));
- -
- - // pause anything that may happen to be parsing right now
- - pause_parse();
- -
- - try
- - {
- - // now start parsing the EFF
- - read_file_text(filename, dir_type, file_text, file_text_raw);
- - reset_parse(file_text);
- -
- - required_string("$Type:");
- - stuff_string(ext, F_NAME, sizeof(ext));
- -
- - required_string("$Frames:");
- - stuff_int(&frames);
- -
- - if (optional_string("$FPS:"))
- - stuff_int(&fps);
- -
- - if (optional_string("$Keyframe:"))
- - stuff_int(&keyframe);
- - }
- - catch (const parse::ParseException& e)
- - {
- - mprintf(("BMPMAN: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
- - unpause_parse();
- - return false;
- - }
- -
- - // done with EFF so unpause parsing so whatever can continue
- - unpause_parse();
- -
- - if (!stricmp(NOX("dds"), ext)) {
- - c_type = BM_TYPE_DDS;
- - } else if (!stricmp(NOX("tga"), ext)) {
- - c_type = BM_TYPE_TGA;
- - } else if (!stricmp(NOX("png"), ext)) {
- - c_type = BM_TYPE_PNG;
- - } else if (!stricmp(NOX("jpg"), ext)) {
- - c_type = BM_TYPE_JPG;
- - } else if (!stricmp(NOX("pcx"), ext)) {
- - c_type = BM_TYPE_PCX;
- - } else {
- - mprintf(("BMPMAN: Unknown file type in EFF parse!\n"));
- - return false;
- - }
- -
- - // did we do anything?
- - if (c_type == BM_TYPE_NONE || frames == 0) {
- - mprintf(("BMPMAN: EFF parse ERROR!\n"));
- - return false;
- - }
- -
- - if (type)
- - *type = c_type;
- -
- - if (nframes)
- - *nframes = frames;
- -
- - if (nfps)
- - *nfps = fps;
- -
- - if (key)
- - *key = keyframe;
- -
- - return true;
- -}
- -
- -int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type) {
- - int i, n;
- - anim the_anim;
- - CFILE *img_cfp = NULL;
- - char filename[MAX_FILENAME_LEN];
- - int reduced = 0;
- - int anim_fps = 0, anim_frames = 0, key = 0;
- - int anim_width = 0, anim_height = 0;
- - BM_TYPE type = BM_TYPE_NONE, eff_type = BM_TYPE_NONE, c_type = BM_TYPE_NONE;
- - int bpp = 0, mm_lvl = 0, img_size = 0;
- - char clean_name[MAX_FILENAME_LEN];
- -
- - if (!bm_inited)
- - bm_init();
- -
- - // set defaults for frame count and fps before going any further
- - if (nframes)
- - *nframes = 0;
- -
- - if (fps)
- - *fps = 0;
- -
- - if (keyframe)
- - *keyframe = 0;
- -
- - memset(filename, 0, MAX_FILENAME_LEN);
- - strncpy(filename, real_filename, MAX_FILENAME_LEN - 1);
- - char *p = strchr(filename, '.');
- - if (p) {
- - mprintf(("Someone passed an extension to bm_load_animation for file '%s'\n", real_filename));
- - *p = 0;
- - }
- -
- - // If we are standalone server keep replacing the 'cursorweb' (mouse cursor) as the filename
- - // should keep the game happy while loading only single ani file which the needs to be present in any case
- - if (Is_standalone) {
- - char standalone_filename[MAX_FILENAME_LEN] = "cursorweb";
- - strcpy_s(filename, standalone_filename);
- - }
- -
- - // safety catch for strcat...
- - // MAX_FILENAME_LEN-5 == '.' plus 3 letter ext plus NULL terminator
- - if (strlen(filename) > MAX_FILENAME_LEN - 5) {
- - 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);
- - return -1;
- - }
- -
- - // used later if EFF type
- - strcpy_s(clean_name, filename);
- -
- - // Lets find out what type it is
- - {
- - int handle = -1;
- -
- - // do a search for any previously loaded files (looks at filename only)
- - if (bm_load_sub_fast(filename, &handle, dir_type, true)) {
- - n = handle % MAX_BITMAPS;
- - Assert(bm_bitmaps[n].handle == handle);
- -
- - if (nframes)
- - *nframes = bm_bitmaps[n].info.ani.num_frames;
- + if (nframes)
- + *nframes = bm_bitmaps[n].info.ani.num_frames;
- if (fps)
- *fps = bm_bitmaps[n].info.ani.fps;
- @@ -1183,13 +916,13 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
- }
- // if we are still here then we need to fall back to a file-based search
- - int rval = bm_load_sub_slow(filename, BM_ANI_NUM_TYPES, bm_ani_ext_list, &img_cfp, dir_type);
- + int rval = bm_load_sub_slow(filename, NUM_TYPES, ext_list, &img_cfp, dir_type);
- if (rval < 0)
- return -1;
- - strcat_s(filename, bm_ani_ext_list[rval]);
- - type = bm_ani_type_list[rval];
- + strcat_s(filename, ext_list[rval]);
- + type = type_list[rval];
- }
- // 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
- @@ -1204,10 +937,11 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
- // it's an effect file, any readable image type with eff being txt
- if (type == BM_TYPE_EFF) {
- - if (!bm_load_and_parse_eff(filename, dir_type, &anim_frames, &anim_fps, &key, &eff_type)) {
- + if (bm_load_and_parse_eff(filename, dir_type, &anim_frames, &anim_fps, &key, &eff_type) != 0) {
- mprintf(("BMPMAN: Error reading EFF\n"));
- return -1;
- - } else {
- + }
- + else {
- mprintf(("BMPMAN: Found EFF (%s) with %d frames at %d fps.\n", filename, anim_frames, anim_fps));
- }
- }
- @@ -1232,7 +966,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
- the_anim.keys = (key_frame*)vm_malloc(sizeof(key_frame) * the_anim.num_keys);
- Assert(the_anim.keys != NULL);
- - for (i = 0; i<the_anim.num_keys; i++) {
- + for (i = 0;i<the_anim.num_keys;i++) {
- the_anim.keys[i].frame_num = 0;
- cfread(&the_anim.keys[i].frame_num, 2, 1, img_cfp);
- cfread(&the_anim.keys[i].offset, 4, 1, img_cfp);
- @@ -1241,11 +975,9 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
- }
- //some retail anis have their keyframes reversed
- key = MAX(the_anim.keys[0].frame_num, the_anim.keys[1].frame_num);
- -
- - vm_free(the_anim.keys);
- - the_anim.keys = nullptr;
- }
- - } else {
- + }
- + else {
- return -1;
- }
- @@ -1254,7 +986,8 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
- reduced = 1;
- anim_frames = (anim_frames + 1) / 2;
- anim_fps = (anim_fps / 2);
- - } else if (Bm_low_mem == 2) {
- + }
- + else if (Bm_low_mem == 2) {
- anim_frames = 1;
- }
- }
- @@ -1271,6 +1004,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
- int first_handle = bm_get_next_handle();
- + Assert(strlen(filename) < MAX_FILENAME_LEN);
- for (i = 0; i < anim_frames; i++) {
- memset(&bm_bitmaps[n + i], 0, sizeof(bitmap_entry));
- @@ -1331,14 +1065,15 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
- bm_bitmaps[n + i].handle = first_handle*MAX_BITMAPS + n + i;
- bm_bitmaps[n + i].last_used = -1;
- bm_bitmaps[n + i].num_mipmaps = mm_lvl;
- - bm_bitmaps[n + i].mem_taken = (size_t)img_size;
- + bm_bitmaps[n + i].mem_taken = img_size;
- bm_bitmaps[n + i].dir_type = dir_type;
- bm_bitmaps[n + i].load_count++;
- if (i == 0) {
- sprintf(bm_bitmaps[n + i].filename, "%s", filename);
- - } else {
- + }
- + else {
- sprintf(bm_bitmaps[n + i].filename, "%s[%d]", filename, i);
- }
- @@ -1359,28 +1094,15 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
- return bm_bitmaps[n].handle;
- }
- -int bm_load_duplicate(const char *filename) {
- - int ret;
- -
- - // ignore duplicates
- - Bm_ignore_duplicates = 1;
- -
- - // load
- - ret = bm_load(filename);
- -
- - // back to normal
- - Bm_ignore_duplicates = 0;
- -
- - return ret;
- -}
- -
- -int bm_load_either(const char *filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type) {
- +int bm_load_either(const char *filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
- +{
- if (nframes != NULL)
- *nframes = 0;
- if (fps != NULL)
- *fps = 0;
- int tidx = bm_load_animation(filename, nframes, fps, keyframe, can_drop_frames, dir_type);
- - if (tidx == -1) {
- + if (tidx == -1)
- + {
- tidx = bm_load(filename);
- if (tidx != -1 && nframes != NULL)
- *nframes = 1;
- @@ -1389,161 +1111,181 @@ int bm_load_either(const char *filename, int *nframes, int *fps, int *keyframe,
- return tidx;
- }
- -int bm_load_sub_fast(const char *real_filename, int *handle, int dir_type, bool animated_type) {
- - if (Bm_ignore_duplicates)
- - return 0;
- -
- - int i;
- +/**
- +* Sanity check to ensure invalid bitmap handles are picked up early
- +*
- +* Some early known false or out of range handles (such as negative) are checked within
- +* an initial routine pass, followed by a more thorough check routine to ensure the
- +* series of bitmaps within the bm_bitmaps[] structure have not become invalid.
- +*
- +* @param handle Bitmap handle to check for validity
- +* @return 1 for valid, 0 for invalid
- +*/
- +int bm_is_valid(int handle)
- +{
- + // Ensure that certain known false or out of range handles are quickly returned as invalid,
- + // prior to utilising the handle in a way which leads to memory access outside bm_bitmaps[]
- + if (!bm_inited) return 0;
- + if (handle < 0) return 0;
- - for (i = 0; i < MAX_BITMAPS; i++) {
- - if (bm_bitmaps[i].type == BM_TYPE_NONE)
- - continue;
- + return (bm_bitmaps[handle % MAX_BITMAPS].handle == handle);
- +}
- - if (bm_bitmaps[i].dir_type != dir_type)
- - continue;
- +/**
- +* Gets info.
- +* w,h,flags,nframes or fps can be NULL if you don't care.
- +*/
- +int bm_get_info(int handle, int *w, int * h, ubyte * flags, int *nframes, int *fps)
- +{
- + bitmap * bmp;
- - bool animated = ((bm_bitmaps[i].type == BM_TYPE_EFF) || (bm_bitmaps[i].type == BM_TYPE_ANI));
- + if (!bm_inited) return -1;
- - if (animated_type && !animated)
- - continue;
- - else if (!animated_type && animated)
- - continue;
- + int bitmapnum = handle % MAX_BITMAPS;
- - if (!strextcmp(real_filename, bm_bitmaps[i].filename)) {
- - nprintf(("BmpFastLoad", "Found bitmap %s -- number %d\n", bm_bitmaps[i].filename, i));
- - bm_bitmaps[i].load_count++;
- - *handle = bm_bitmaps[i].handle;
- - return 1;
- - }
- +#ifndef NDEBUG
- + if (bm_bitmaps[bitmapnum].handle != handle) {
- + mprintf(("bm_get_info - %s: bm_bitmaps[%d].handle = %d, handle = %d\n", bm_bitmaps[bitmapnum].filename, bitmapnum, bm_bitmaps[bitmapnum].handle, handle));
- }
- +#endif
- - // not found to be loaded already
- - return 0;
- -}
- -
- -int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **ext_list, CFILE **img_cfp, int dir_type) {
- - char full_path[MAX_PATH];
- - int size = 0, offset = 0;
- - int rval = -1;
- -
- - rval = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, sizeof(full_path) - 1, full_path, &size, &offset, 0);
- + 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!
- - // could not be found, or is invalid for some reason
- - if ((rval < 0) || (rval >= num_ext))
- + if ((bm_bitmaps[bitmapnum].type == BM_TYPE_NONE) || (bm_bitmaps[bitmapnum].handle != handle)) {
- + if (w) *w = 0;
- + if (h) *h = 0;
- + if (flags) *flags = 0;
- + if (nframes) *nframes = 0;
- + if (fps) *fps = 0;
- return -1;
- + }
- - CFILE *test = cfopen_special(full_path, "rb", size, offset, dir_type);
- + bmp = &(bm_bitmaps[bitmapnum].bm);
- - if (test != NULL) {
- - if (img_cfp != NULL)
- - *img_cfp = test;
- + if (w) *w = bmp->w;
- + if (h) *h = bmp->h;
- + if (flags) *flags = bmp->flags;
- - return rval;
- + if ((bm_bitmaps[bitmapnum].type == BM_TYPE_ANI) || (bm_bitmaps[bitmapnum].type == BM_TYPE_EFF)) {
- + if (nframes) {
- + *nframes = bm_bitmaps[bitmapnum].info.ani.num_frames;
- + }
- + if (fps) {
- + *fps = bm_bitmaps[bitmapnum].info.ani.fps;
- + }
- +
- + return bm_bitmaps[bm_bitmaps[bitmapnum].info.ani.first_frame].handle;
- }
- + else {
- + if (nframes) {
- + *nframes = 1;
- + }
- + if (fps) {
- + *fps = 0;
- + }
- - // umm, that's not good...
- - return -1;
- + return handle;
- + }
- }
- -bitmap * bm_lock(int handle, ubyte bpp, ubyte flags, bool nodebug) {
- - bitmap *bmp;
- - bitmap_entry *be;
- -
- +/**
- +* Gets the image type
- +*/
- +ubyte bm_get_type(int handle)
- +{
- if (!bm_inited) bm_init();
- int bitmapnum = handle % MAX_BITMAPS;
- + 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!
- - 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
- + return bm_bitmaps[bitmapnum].type;
- +}
- - // to fix a couple of OGL bpp passes, force 8bit on AABITMAP - taylor
- - if (flags & BMP_AABITMAP)
- - bpp = 8;
- +static void bm_convert_format(bitmap *bmp, ubyte flags)
- +{
- + int idx;
- +
- + // no transparency for 24 bpp images
- + if (!(flags & BMP_AABITMAP) && (bmp->bpp == 24))
- + return;
- - // if we're on a standalone server, aways for it to lock to 8 bits
- if (Is_standalone) {
- - bpp = 8;
- - flags = 0;
- + Assert(bmp->bpp == 8);
- + return;
- }
- - // otherwise do it as normal
- else {
- - if (flags & BMP_AABITMAP) {
- - Assert(bpp == 8);
- - } else if ((flags & BMP_TEX_NONCOMP) && (!(flags & BMP_TEX_COMP))) {
- - Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
- - } else if ((flags & BMP_TEX_DXT1) || (flags & BMP_TEX_DXT3) || (flags & BMP_TEX_DXT5)) {
- - Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
- - } else if (flags & BMP_TEX_CUBEMAP) {
- - Assert((bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DDS) ||
- - (bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DXT1) ||
- - (bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DXT3) ||
- - (bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DXT5));
- - Assert(bpp >= 16);
- - } else {
- - Assert(0); //?
- + if (flags & BMP_AABITMAP)
- + Assert(bmp->bpp == 8);
- + else
- + Assert((bmp->bpp == 16) || (bmp->bpp == 32));
- + }
- +
- + // maybe swizzle to be an xparent texture
- + if (!(bmp->flags & BMP_TEX_XPARENT) && (flags & BMP_TEX_XPARENT)) {
- + for (idx = 0; idx<bmp->w*bmp->h; idx++) {
- + // if the pixel is transparent
- + if (((ushort*)bmp->data)[idx] == Gr_t_green.mask) {
- + ((ushort*)bmp->data)[idx] = 0;
- + }
- }
- +
- + bmp->flags |= BMP_TEX_XPARENT;
- }
- +}
- - be = &bm_bitmaps[bitmapnum];
- - bmp = &be->bm;
- +// basically, map the bitmap into the current palette. used to be done for all pcx's, now just for
- +// Fred, since its the only thing that uses the software tmapper
- +void bm_swizzle_8bit_for_fred(bitmap_entry *be, bitmap *bmp, ubyte *data, ubyte *palette)
- +{
- + /* 2004/10/17 - taylor - no longer needed since FRED is OGL now*/
- +}
- - // If you hit this assert, chances are that someone freed the
- - // wrong bitmap and now someone is trying to use that bitmap.
- - // See John.
- - Assert(be->type != BM_TYPE_NONE);
- +void bm_lock_pcx(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
- +{
- + ubyte *data;
- + int pcx_error;
- + char filename[MAX_FILENAME_LEN];
- - // Increment ref count for bitmap since lock was made on it.
- - Assert(be->ref_count >= 0);
- - be->ref_count++; // Lock it before we page in data; this prevents a callback from freeing this
- - // as it gets read in
- + // Unload any existing data
- + bm_free_data(bitmapnum);
- +
- + be->mem_taken = (bmp->w * bmp->h * (bpp >> 3));
- + data = (ubyte *)bm_malloc(bitmapnum, be->mem_taken);
- + bmp->bpp = bpp;
- + bmp->data = (ptr_u)data;
- + bmp->palette = (bpp == 8) ? gr_palette : NULL;
- + memset(data, 0, be->mem_taken);
- - // Mark this bitmap as used this frame
- + Assert(&be->bm == bmp);
- #ifdef BMPMAN_NDEBUG
- - if (be->used_this_frame < 255) {
- - be->used_this_frame++;
- - }
- + Assert(be->data_size > 0);
- #endif
- - // read the file data
- - if (gr_bm_lock(be->filename, handle, bitmapnum, bpp, flags, nodebug) == -1) {
- - // oops, this isn't good - reset and return NULL
- - bm_unlock( handle );
- - bm_unload( handle );
- -
- - return NULL;
- - }
- + // some sanity checks on flags
- + Assert(!((flags & BMP_AABITMAP) && (flags & BMP_TEX_ANY))); // no aabitmap textures
- - MONITOR_INC(NumBitmapPage, 1);
- - MONITOR_INC(SizeBitmapPage, bmp->w*bmp->h);
- + // make sure we are using the correct filename in the case of an EFF.
- + // this will populate filename[] whether it's EFF or not
- + EFF_FILENAME_CHECK;
- - if ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF)) {
- - int i, first = bm_bitmaps[bitmapnum].info.ani.first_frame;
- + pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), 0, be->dir_type);
- - for (i = 0; i< bm_bitmaps[first].info.ani.num_frames; i++) {
- - // Mark all the bitmaps in this bitmap or animation as recently used
- - bm_bitmaps[first + i].last_used = timer_get_milliseconds();
- + if (pcx_error != PCX_ERROR_NONE) {
- + mprintf(("Couldn't load PCX!!! (%s)\n", filename));
- + return;
- + }
- #ifdef BMPMAN_NDEBUG
- - // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
- - bm_bitmaps[first + i].used_count++;
- -#endif
- -
- - bm_bitmaps[first + i].used_flags = flags;
- - }
- - } else {
- - // Mark all the bitmaps in this bitmap or animation as recently used
- - be->last_used = timer_get_milliseconds();
- + Assert(be->data_size > 0);
- +#endif
- -#ifdef BMPMAN_NDEBUG
- - // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
- - be->used_count++;
- -#endif
- - be->used_flags = flags;
- - }
- + bmp->flags = 0;
- - return bmp;
- + bm_convert_format(bmp, flags);
- }
- -void bm_lock_ani(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
- +void bm_lock_ani(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
- +{
- anim *the_anim;
- anim_instance *the_anim_instance;
- bitmap *bm;
- @@ -1573,7 +1315,7 @@ void bm_lock_ani(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte
- bm = &bm_bitmaps[first_frame].bm;
- size = bm->w * bm->h * (bpp >> 3);
- - be->mem_taken = (size_t)size;
- + be->mem_taken = size;
- Assert(size > 0);
- @@ -1646,7 +1388,8 @@ void bm_lock_ani(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte
- v += dv;
- }
- }
- - } else {
- + }
- + else {
- // 1-to-1 mapping
- memcpy(dptr, sptr, size);
- }
- @@ -1663,7 +1406,114 @@ void bm_lock_ani(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte
- anim_free(the_anim);
- }
- -void bm_lock_dds(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
- +
- +void bm_lock_user(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
- +{
- + // Unload any existing data
- + bm_free_data(bitmapnum);
- +
- + if ((bpp != be->info.user.bpp) && !(flags & BMP_AABITMAP))
- + bpp = be->info.user.bpp;
- +
- + switch (bpp) {
- + case 32: // user 32-bit bitmap
- + bmp->bpp = bpp;
- + bmp->flags = be->info.user.flags;
- + bmp->data = (ptr_u)be->info.user.data;
- + break;
- +
- + case 24: // user 24-bit bitmap
- + bmp->bpp = bpp;
- + bmp->flags = be->info.user.flags;
- + bmp->data = (ptr_u)be->info.user.data;
- + break;
- +
- + case 16: // user 16 bit bitmap
- + bmp->bpp = bpp;
- + bmp->flags = be->info.user.flags;
- + bmp->data = (ptr_u)be->info.user.data;
- + break;
- +
- + case 8: // Going from 8 bpp to something (probably only for aabitmaps)
- + Assert(flags & BMP_AABITMAP);
- + bmp->bpp = bpp;
- + bmp->flags = be->info.user.flags;
- + bmp->data = (ptr_u)be->info.user.data;
- + break;
- +
- + default:
- + Error(LOCATION, "Unhandled user bitmap conversion from %d to %d bpp", be->info.user.bpp, bmp->bpp);
- + break;
- + }
- +
- + bm_convert_format(bmp, flags);
- +}
- +
- +void bm_lock_tga(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
- +{
- + ubyte *data = NULL;
- + int d_size, byte_size;
- + char filename[MAX_FILENAME_LEN];
- +
- + // Unload any existing data
- + bm_free_data(bitmapnum);
- +
- + if (Is_standalone) {
- + Assert(bpp == 8);
- + }
- + else
- + {
- + Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
- + }
- +
- + // allocate bitmap data
- + byte_size = (bpp >> 3);
- +
- + Assert(byte_size);
- + Assert(be->mem_taken > 0);
- +
- + data = (ubyte*)bm_malloc(bitmapnum, be->mem_taken);
- +
- + if (data) {
- + memset(data, 0, be->mem_taken);
- + d_size = byte_size;
- + }
- + else {
- + return;
- + }
- +
- + bmp->bpp = bpp;
- + bmp->data = (ptr_u)data;
- + bmp->palette = NULL;
- +
- + Assert(&be->bm == bmp);
- +#ifdef BMPMAN_NDEBUG
- + Assert(be->data_size > 0);
- +#endif
- +
- + int tga_error;
- +
- + // make sure we are using the correct filename in the case of an EFF.
- + // this will populate filename[] whether it's EFF or not
- + EFF_FILENAME_CHECK;
- +
- + tga_error = targa_read_bitmap(filename, data, NULL, d_size, be->dir_type);
- +
- + if (tga_error != TARGA_ERROR_NONE) {
- + bm_free_data(bitmapnum);
- + return;
- + }
- +
- + bmp->flags = 0;
- +
- + bm_convert_format(bmp, flags);
- +}
- +
- +/**
- +* Lock a DDS file
- +*/
- +void bm_lock_dds(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
- +{
- ubyte *data = NULL;
- int error;
- ubyte dds_bpp = 0;
- @@ -1691,19 +1541,20 @@ void bm_lock_dds(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte
- #if BYTE_ORDER == BIG_ENDIAN
- // same as with TGA, we need to byte swap 16 & 32-bit, uncompressed, DDS images
- if ((be->comp_type == BM_TYPE_DDS) || (be->comp_type == BM_TYPE_CUBEMAP_DDS)) {
- - size_t i = 0;
- + unsigned int i = 0;
- if (dds_bpp == 32) {
- unsigned int *swap_tmp;
- - for (i = 0; i < be->mem_taken; i += 4) {
- + for (i = 0; i < (unsigned int)be->mem_taken; i += 4) {
- swap_tmp = (unsigned int *)(data + i);
- *swap_tmp = INTEL_INT(*swap_tmp);
- }
- - } else if (dds_bpp == 16) {
- + }
- + else if (dds_bpp == 16) {
- unsigned short *swap_tmp;
- - for (i = 0; i < be->mem_taken; i += 2) {
- + for (i = 0; i < (unsigned int)be->mem_taken; i += 2) {
- swap_tmp = (unsigned short *)(data + i);
- *swap_tmp = INTEL_SHORT(*swap_tmp);
- }
- @@ -1725,92 +1576,11 @@ void bm_lock_dds(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte
- #endif
- }
- -void bm_lock_jpg(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
- - ubyte *data = NULL;
- - int d_size = 0;
- - int jpg_error = JPEG_ERROR_INVALID;
- - char filename[MAX_FILENAME_LEN];
- -
- - // Unload any existing data
- - bm_free_data(bitmapnum);
- -
- - d_size = (bpp >> 3);
- -
- - // allocate bitmap data
- - Assert(be->mem_taken > 0);
- - data = (ubyte*)bm_malloc(bitmapnum, be->mem_taken);
- -
- - if (data == NULL)
- - return;
- -
- - memset(data, 0, be->mem_taken);
- -
- - bmp->bpp = bpp;
- - bmp->data = (ptr_u)data;
- - bmp->palette = NULL;
- -
- - Assert(&be->bm == bmp);
- -
- - // make sure we are using the correct filename in the case of an EFF.
- - // this will populate filename[] whether it's EFF or not
- - EFF_FILENAME_CHECK;
- -
- - jpg_error = jpeg_read_bitmap(filename, data, NULL, d_size, be->dir_type);
- -
- - if (jpg_error != JPEG_ERROR_NONE) {
- - bm_free_data(bitmapnum);
- - return;
- - }
- -
- -#ifdef BMPMAN_NDEBUG
- - Assert(be->data_size > 0);
- -#endif
- -}
- -
- -void bm_lock_pcx(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
- - ubyte *data;
- - int pcx_error;
- - char filename[MAX_FILENAME_LEN];
- -
- - // Unload any existing data
- - bm_free_data(bitmapnum);
- -
- - be->mem_taken = (bmp->w * bmp->h * (bpp >> 3));
- - data = (ubyte *)bm_malloc(bitmapnum, be->mem_taken);
- - bmp->bpp = bpp;
- - bmp->data = (ptr_u)data;
- - bmp->palette = (bpp == 8) ? gr_palette : NULL;
- - memset(data, 0, be->mem_taken);
- -
- - Assert(&be->bm == bmp);
- -#ifdef BMPMAN_NDEBUG
- - Assert(be->data_size > 0);
- -#endif
- -
- - // some sanity checks on flags
- - Assert(!((flags & BMP_AABITMAP) && (flags & BMP_TEX_ANY))); // no aabitmap textures
- -
- - // make sure we are using the correct filename in the case of an EFF.
- - // this will populate filename[] whether it's EFF or not
- - EFF_FILENAME_CHECK;
- -
- - pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), 0, be->dir_type);
- -
- - if (pcx_error != PCX_ERROR_NONE) {
- - mprintf(("Couldn't load PCX!!! (%s)\n", filename));
- - return;
- - }
- -
- -#ifdef BMPMAN_NDEBUG
- - Assert(be->data_size > 0);
- -#endif
- -
- - bmp->flags = 0;
- -
- - bm_convert_format(bmp, flags);
- -}
- -
- -void bm_lock_png(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
- +/**
- +* Lock a PNG file
- +*/
- +void bm_lock_png(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
- +{
- ubyte *data = NULL;
- //assume 32 bit - libpng should expand everything
- int d_size;
- @@ -1853,191 +1623,640 @@ void bm_lock_png(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte
- #endif
- }
- -void bm_lock_tga(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
- +/**
- +* Lock a JPEG file
- +*/
- +void bm_lock_jpg(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags)
- +{
- ubyte *data = NULL;
- - int d_size, byte_size;
- + int d_size = 0;
- + int jpg_error = JPEG_ERROR_INVALID;
- char filename[MAX_FILENAME_LEN];
- // Unload any existing data
- bm_free_data(bitmapnum);
- - if (Is_standalone) {
- - Assert(bpp == 8);
- - } else {
- - Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
- - }
- + d_size = (bpp >> 3);
- // allocate bitmap data
- - byte_size = (bpp >> 3);
- -
- - Assert(byte_size);
- Assert(be->mem_taken > 0);
- -
- data = (ubyte*)bm_malloc(bitmapnum, be->mem_taken);
- - if (data) {
- - memset(data, 0, be->mem_taken);
- - d_size = byte_size;
- - } else {
- + if (data == NULL)
- return;
- - }
- +
- + memset(data, 0, be->mem_taken);
- bmp->bpp = bpp;
- bmp->data = (ptr_u)data;
- bmp->palette = NULL;
- Assert(&be->bm == bmp);
- -#ifdef BMPMAN_NDEBUG
- - Assert(be->data_size > 0);
- -#endif
- -
- - int tga_error;
- // make sure we are using the correct filename in the case of an EFF.
- // this will populate filename[] whether it's EFF or not
- EFF_FILENAME_CHECK;
- - tga_error = targa_read_bitmap(filename, data, NULL, d_size, be->dir_type);
- + jpg_error = jpeg_read_bitmap(filename, data, NULL, d_size, be->dir_type);
- - if (tga_error != TARGA_ERROR_NONE) {
- + if (jpg_error != JPEG_ERROR_NONE) {
- bm_free_data(bitmapnum);
- return;
- }
- - bmp->flags = 0;
- -
- - bm_convert_format(bmp, flags);
- +#ifdef BMPMAN_NDEBUG
- + Assert(be->data_size > 0);
- +#endif
- }
- -void bm_lock_user(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, ubyte bpp, ubyte flags) {
- - // Unload any existing data
- - bm_free_data(bitmapnum);
- +MONITOR(NumBitmapPage)
- +MONITOR(SizeBitmapPage)
- - if ((bpp != be->info.user.bpp) && !(flags & BMP_AABITMAP))
- - bpp = be->info.user.bpp;
- +/**
- +* This locks down a bitmap and returns a pointer to a bitmap that can be accessed until you call bm_unlock.
- +*
- +* Only lock a bitmap when you need it! This will convert it into the appropriate format also.
- +*/
- +bitmap * bm_lock(int handle, ubyte bpp, ubyte flags, bool nodebug)
- +{
- + bitmap *bmp;
- + bitmap_entry *be;
- - switch (bpp) {
- - case 32: // user 32-bit bitmap
- - bmp->bpp = bpp;
- - bmp->flags = be->info.user.flags;
- - bmp->data = (ptr_u)be->info.user.data;
- - break;
- + if (!bm_inited) bm_init();
- - case 24: // user 24-bit bitmap
- - bmp->bpp = bpp;
- - bmp->flags = be->info.user.flags;
- - bmp->data = (ptr_u)be->info.user.data;
- - break;
- + int bitmapnum = handle % MAX_BITMAPS;
- - case 16: // user 16 bit bitmap
- - bmp->bpp = bpp;
- - bmp->flags = be->info.user.flags;
- - bmp->data = (ptr_u)be->info.user.data;
- - break;
- + 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
- - case 8: // Going from 8 bpp to something (probably only for aabitmaps)
- - Assert(flags & BMP_AABITMAP);
- - bmp->bpp = bpp;
- - bmp->flags = be->info.user.flags;
- - bmp->data = (ptr_u)be->info.user.data;
- - break;
- + // to fix a couple of OGL bpp passes, force 8bit on AABITMAP - taylor
- + if (flags & BMP_AABITMAP)
- + bpp = 8;
- - default:
- - Error(LOCATION, "Unhandled user bitmap conversion from %d to %d bpp", be->info.user.bpp, bmp->bpp);
- - break;
- + // if we're on a standalone server, aways for it to lock to 8 bits
- + if (Is_standalone) {
- + bpp = 8;
- + flags = 0;
- + }
- + // otherwise do it as normal
- + else {
- + if (flags & BMP_AABITMAP) {
- + Assert(bpp == 8);
- + }
- + else if ((flags & BMP_TEX_NONCOMP) && (!(flags & BMP_TEX_COMP))) {
- + Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
- + }
- + else if ((flags & BMP_TEX_DXT1) || (flags & BMP_TEX_DXT3) || (flags & BMP_TEX_DXT5)) {
- + Assert(bpp >= 16); // cheating but bpp passed isn't what we normally end up with
- + }
- + else if (flags & BMP_TEX_CUBEMAP) {
- + Assert((bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DDS) ||
- + (bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DXT1) ||
- + (bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DXT3) ||
- + (bm_bitmaps[bitmapnum].type == BM_TYPE_CUBEMAP_DXT5));
- + Assert(bpp >= 16);
- + }
- + else {
- + Assert(0); //?
- + }
- }
- - bm_convert_format(bmp, flags);
- -}
- + be = &bm_bitmaps[bitmapnum];
- + bmp = &be->bm;
- -int bm_make_render_target(int width, int height, int flags) {
- - int i, n;
- - int mm_lvl = 0;
- - // final w and h may be different from passed width and height
- - int w = width, h = height;
- - ubyte bpp = 32;
- - int size = 0;
- + // If you hit this assert, chances are that someone freed the
- + // wrong bitmap and now someone is trying to use that bitmap.
- + // See John.
- + Assert(be->type != BM_TYPE_NONE);
- - if (!bm_inited)
- - bm_init();
- + // Increment ref count for bitmap since lock was made on it.
- + Assert(be->ref_count >= 0);
- + be->ref_count++; // Lock it before we page in data; this prevents a callback from freeing this
- + // as it gets read in
- - // Find an open slot (starting from the end)
- - for (n = -1, i = MAX_BITMAPS - 1; i >= 0; i--) {
- - if (bm_bitmaps[i].type == BM_TYPE_NONE) {
- - n = i;
- - break;
- - }
- + // Mark this bitmap as used this frame
- +#ifdef BMPMAN_NDEBUG
- + if (be->used_this_frame < 255) {
- + be->used_this_frame++;
- }
- +#endif
- - // Out of bitmap slots
- - if (n == -1)
- - return -1;
- + // read the file data
- + if (gr_bm_lock(be->filename, handle, bitmapnum, bpp, flags, nodebug) == -1) {
- + // oops, this isn't good - reset and return NULL
- + bm_unlock(bitmapnum);
- + bm_unload(bitmapnum);
- - if (!gr_bm_make_render_target(n, &w, &h, &bpp, &mm_lvl, flags))
- - return -1;
- + return NULL;
- + }
- - Assert(mm_lvl > 0);
- + MONITOR_INC(NumBitmapPage, 1);
- + MONITOR_INC(SizeBitmapPage, bmp->w*bmp->h);
- - if (flags & BMP_FLAG_RENDER_TARGET_STATIC) {
- - // data size
- - size = (w * h * (bpp >> 3));
- + if ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF)) {
- + int i, first = bm_bitmaps[bitmapnum].info.ani.first_frame;
- - if (mm_lvl > 1) {
- - // include size of all mipmap levels (there should be a full chain)
- - size += (size / 3) - 1;
- - }
- + for (i = 0; i< bm_bitmaps[first].info.ani.num_frames; i++) {
- + // Mark all the bitmaps in this bitmap or animation as recently used
- + bm_bitmaps[first + i].last_used = timer_get_milliseconds();
- - // make sure to count all faces if a cubemap
- - if (flags & BMP_FLAG_CUBEMAP) {
- - size *= 6;
- +#ifdef BMPMAN_NDEBUG
- + // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
- + bm_bitmaps[first + i].used_count++;
- +#endif
- +
- + bm_bitmaps[first + i].used_flags = flags;
- }
- }
- + else {
- + // Mark all the bitmaps in this bitmap or animation as recently used
- + be->last_used = timer_get_milliseconds();
- - // ensure fields are cleared out from previous bitmap
- - memset(&bm_bitmaps[n], 0, sizeof(bitmap_entry));
- +#ifdef BMPMAN_NDEBUG
- + // Mark all the bitmaps in this bitmap or animation as used for the usage tracker.
- + be->used_count++;
- +#endif
- + be->used_flags = flags;
- + }
- - bm_bitmaps[n].type = (flags & BMP_FLAG_RENDER_TARGET_STATIC) ? BM_TYPE_RENDER_TARGET_STATIC : BM_TYPE_RENDER_TARGET_DYNAMIC;
- - bm_bitmaps[n].signature = Bm_next_signature++;
- - sprintf(bm_bitmaps[n].filename, "RT_%dx%d+%d", w, h, bpp);
- - bm_bitmaps[n].bm.w = (short)w;
- - bm_bitmaps[n].bm.h = (short)h;
- - bm_bitmaps[n].bm.rowsize = (short)w;
- - bm_bitmaps[n].bm.bpp = (ubyte)bpp;
- - bm_bitmaps[n].bm.true_bpp = (ubyte)bpp;
- - bm_bitmaps[n].bm.flags = (ubyte)flags;
- - bm_bitmaps[n].bm.data = 0;
- - bm_bitmaps[n].bm.palette = NULL;
- - bm_bitmaps[n].num_mipmaps = mm_lvl;
- - bm_bitmaps[n].mem_taken = (size_t)size;
- - bm_bitmaps[n].dir_type = CF_TYPE_ANY;
- + return bmp;
- +}
- +
- +/**
- +* Unlocks a bitmap
- +*
- +* Decrements the ref_count member of the bitmap_entry struct. A bitmap can only be unloaded
- +* when the ref_count is 0.
- +*/
- +void bm_unlock(int handle)
- +{
- + bitmap_entry *be;
- + bitmap *bmp;
- +
- + if (!bm_inited) bm_init();
- +
- + int bitmapnum = handle % MAX_BITMAPS;
- +
- +#ifndef NDEBUG
- + if (bm_bitmaps[bitmapnum].handle != handle) {
- + mprintf(("bm_unlock - %s: bm_bitmaps[%d].handle = %d, handle = %d\n", bm_bitmaps[bitmapnum].filename, bitmapnum, bm_bitmaps[bitmapnum].handle, handle));
- + }
- +#endif
- +
- + Assert(bm_bitmaps[bitmapnum].handle == handle); // INVALID BITMAP HANDLE
- +
- + Assert((bitmapnum >= 0) && (bitmapnum < MAX_BITMAPS));
- +
- + be = &bm_bitmaps[bitmapnum];
- + bmp = &be->bm;
- +
- + be->ref_count--;
- + Assert(be->ref_count >= 0); // Trying to unlock data more times than lock was called!!!
- +}
- +
- +const char *bm_get_filename(int handle)
- +{
- + int n;
- +
- + n = handle % MAX_BITMAPS;
- + Assert(bm_bitmaps[n].handle == handle); // INVALID BITMAP HANDLE
- + return bm_bitmaps[n].filename;
- +}
- +
- +void bm_get_palette(int handle, ubyte *pal, char *name)
- +{
- + char *filename;
- + int w, h;
- +
- + int n = handle % MAX_BITMAPS;
- + Assert(bm_bitmaps[n].handle == handle); // INVALID BITMAP HANDLE
- +
- + filename = bm_bitmaps[n].filename;
- +
- + if (name) {
- + strcpy(name, filename);
- + }
- +
- + int pcx_error = pcx_read_header(filename, NULL, &w, &h, NULL, pal);
- + if (pcx_error != PCX_ERROR_NONE) {
- + // Error(LOCATION, "Couldn't open '%s'\n", filename );
- + }
- +}
- +
- +/**
- +* Unloads the bitmap's data and entire slot, so bitmap 'handle' won't be valid anymore
- +* NOTE: this releases the slot of EVERY frame in an ANI so don't pass any frame but the first
- +*
- +* @param handle index into ::bm_bitmaps ( index returned from bm_load() or bm_create() )
- +* @param clear_render_targets Whether to release a render target
- +*
- +* @return 1 on successful release, 0 otherwise
- +*/
- +int bm_release(int handle, int clear_render_targets)
- +{
- + Assert(handle >= 0);
- +
- + bitmap_entry *be;
- +
- + int n = handle % MAX_BITMAPS;
- +
- + Assert((n >= 0) && (n < MAX_BITMAPS));
- + be = &bm_bitmaps[n];
- +
- + if (be->type == BM_TYPE_NONE) {
- + return 0; // Already been released?
- + }
- +
- + Assertion(be->handle == handle, "Invalid bitmap handle number %d (expected %d) for %s passed to bm_release()\n", be->handle, handle, be->filename);
- +
- + if (!clear_render_targets && ((be->type == BM_TYPE_RENDER_TARGET_STATIC) || (be->type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
- + nprintf(("BmpMan", "Tried to release a render target!\n"));
- + return 0;
- + }
- +
- + // If it is locked, cannot free it.
- + if (be->ref_count != 0) {
- + nprintf(("BmpMan", "Tried to release %s that has a lock count of %d.. not releasing\n", be->filename, be->ref_count));
- + return 0;
- + }
- +
- + // kind of like ref_count except it gets around the lock/unlock usage problem
- + // this gets set for each bm_load() call so we can make sure and not unload it
- + // from memory, even if we *can*, until it's really not needed anymore
- + if (be->load_count > 0)
- + be->load_count--;
- +
- + if (be->load_count != 0) {
- + nprintf(("BmpMan", "Tried to release %s that has a load count of %d.. not releasing\n", be->filename, be->load_count + 1));
- + return 0;
- + }
- +
- + if (be->type != BM_TYPE_USER) {
- + nprintf(("BmpMan", "Releasing bitmap %s in slot %i with handle %i\n", be->filename, n, handle));
- + }
- +
- + // be sure that all frames of an ani are unloaded - taylor
- + if ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF)) {
- + int i, first = be->info.ani.first_frame, total = bm_bitmaps[first].info.ani.num_frames;
- +
- + for (i = 0; i < total; i++) {
- + bm_free_data(first + i, true); // clears flags, bbp, data, etc
- +
- + memset(&bm_bitmaps[first + i], 0, sizeof(bitmap_entry));
- +
- + bm_bitmaps[first + i].type = BM_TYPE_NONE;
- + bm_bitmaps[first + i].comp_type = BM_TYPE_NONE;
- + bm_bitmaps[first + i].dir_type = CF_TYPE_ANY;
- + // Fill in bogus structures!
- +
- + // For debugging:
- + strcpy_s(bm_bitmaps[first + i].filename, "IVE_BEEN_RELEASED!");
- + bm_bitmaps[first + i].signature = 0xDEADBEEF; // a unique signature identifying the data
- + bm_bitmaps[first + i].palette_checksum = 0xDEADBEEF; // checksum used to be sure bitmap is in current palette
- +
- + // bookeeping
- + bm_bitmaps[first + i].ref_count = -1; // Number of locks on bitmap. Can't unload unless ref_count is 0.
- +
- + // Stuff needed for animations
- + bm_bitmaps[first + i].info.ani.first_frame = -1;
- +
- + bm_bitmaps[first + i].handle = -1;
- + }
- + }
- + else {
- + bm_free_data(n, true); // clears flags, bbp, data, etc
- +
- + memset(&bm_bitmaps[n], 0, sizeof(bitmap_entry));
- +
- + bm_bitmaps[n].type = BM_TYPE_NONE;
- + bm_bitmaps[n].comp_type = BM_TYPE_NONE;
- + bm_bitmaps[n].dir_type = CF_TYPE_ANY;
- + // Fill in bogus structures!
- +
- + // For debugging:
- + strcpy_s(bm_bitmaps[n].filename, "IVE_BEEN_RELEASED!");
- + bm_bitmaps[n].signature = 0xDEADBEEF; // a unique signature identifying the data
- + bm_bitmaps[n].palette_checksum = 0xDEADBEEF; // checksum used to be sure bitmap is in current palette
- +
- + // bookeeping
- + bm_bitmaps[n].ref_count = -1; // Number of locks on bitmap. Can't unload unless ref_count is 0.
- +
- + // Stuff needed for animations
- + bm_bitmaps[n].info.ani.first_frame = -1;
- +
- + bm_bitmaps[n].handle = -1;
- + }
- +
- + return 1;
- +}
- +
- +/**
- +* Unloads the data, but not the bitmap info.
- +*
- +* @param handle index into ::bm_bitmaps ( index returned from bm_load() or bm_create() )
- +* @param clear_render_targets Whether to release a render target
- +* @param nodebug Exclude certain debug messages
- +*
- +* @return 1 on successful release, 0 otherwise
- +*/
- +int bm_unload(int handle, int clear_render_targets, bool nodebug)
- +{
- + bitmap_entry *be;
- + bitmap *bmp;
- +
- + int n = handle % MAX_BITMAPS;
- +
- + Assert((n >= 0) && (n < MAX_BITMAPS));
- + be = &bm_bitmaps[n];
- + bmp = &be->bm;
- +
- + if (!clear_render_targets && ((be->type == BM_TYPE_RENDER_TARGET_STATIC) || (be->type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
- + return -1;
- + }
- +
- + if (be->type == BM_TYPE_NONE) {
- + return -1; // Already been released
- + }
- +
- + Assert(be->handle == handle); // INVALID BITMAP HANDLE!
- +
- + // If it is locked, cannot free it.
- + if (be->ref_count != 0 && !nodebug) {
- + nprintf(("BmpMan", "Tried to unload %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
- + return 0;
- + }
- +
- + // kind of like ref_count except it gets around the lock/unlock usage problem
- + // this gets set for each bm_load() call so we can make sure and not unload it
- + // from memory, even if we *can*, until it's really not needed anymore
- + if (!Bm_ignore_load_count) {
- + if (be->load_count > 0)
- + be->load_count--;
- +
- + if (be->load_count != 0 && !nodebug) {
- + nprintf(("BmpMan", "Tried to unload %s that has a load count of %d.. not unloading\n", be->filename, be->load_count + 1));
- + return 0;
- + }
- + }
- +
- + // be sure that all frames of an ani are unloaded - taylor
- + if ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF)) {
- + int i, first = be->info.ani.first_frame;
- +
- + // for the unload all case, don't try to unload every frame of every frame
- + // all additional frames automatically get unloaded with the first one
- + if ((n > be->info.ani.first_frame) && (bm_bitmaps[first].bm.data == 0))
- + return 1;
- +
- + for (i = 0; i < bm_bitmaps[first].info.ani.num_frames; i++) {
- + if (!nodebug)
- + nprintf(("BmpMan", "Unloading %s frame %d. %dx%dx%d\n", be->filename, i, bmp->w, bmp->h, bmp->bpp));
- + bm_free_data(first + i); // clears flags, bbp, data, etc
- + }
- + }
- + else {
- + if (!nodebug)
- + nprintf(("BmpMan", "Unloading %s. %dx%dx%d\n", be->filename, bmp->w, bmp->h, bmp->bpp));
- + bm_free_data(n); // clears flags, bbp, data, etc
- + }
- +
- + return 1;
- +}
- +
- +/**
- +* Just like bm_unload() except that it doesn't care about what load_count is
- +* and will just plow through and release the data anyway
- +*
- +* NOTE: that bm_free_data_fast() is used here and NOT bm_free_data()!
- +*/
- +int bm_unload_fast(int handle, int clear_render_targets)
- +{
- + bitmap_entry *be;
- + bitmap *bmp;
- +
- + int n = handle % MAX_BITMAPS;
- +
- + Assert((n >= 0) && (n < MAX_BITMAPS));
- + be = &bm_bitmaps[n];
- + bmp = &be->bm;
- +
- + if (be->type == BM_TYPE_NONE) {
- + return -1; // Already been released
- + }
- +
- + if (be->type == BM_TYPE_USER) {
- + return -1;
- + }
- +
- + if (!clear_render_targets && ((be->type == BM_TYPE_RENDER_TARGET_STATIC) || (be->type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
- + return -1;
- + }
- +
- + // If it is locked, cannot free it.
- + if (be->ref_count != 0) {
- + nprintf(("BmpMan", "Tried to unload_fast %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
- + return 0;
- + }
- +
- + Assert(be->handle == handle); // INVALID BITMAP HANDLE!
- +
- + // unlike bm_unload(), we handle each frame of an animation separately, for safer use in the graphics API
- + nprintf(("BmpMan", "Fast-unloading %s. %dx%dx%d\n", be->filename, bmp->w, bmp->h, bmp->bpp));
- + bm_free_data_fast(n); // clears flags, bbp, data, etc
- +
- + return 1;
- +}
- +
- +/**
- +* Unload all used bitmaps
- +*/
- +void bm_unload_all()
- +{
- + int i;
- +
- + // since bm_unload_all() should only be called from game_shutdown() it should be
- + // safe to ignore load_count's and unload anyway
- + Bm_ignore_load_count = 1;
- +
- + for (i = 0; i < MAX_BITMAPS; i++) {
- + if (bm_bitmaps[i].type != BM_TYPE_NONE) {
- + bm_unload(bm_bitmaps[i].handle, 1);
- + }
- + }
- +
- + Bm_ignore_load_count = 0;
- +}
- +
- +
- +DCF(bmpman, "Shows/changes bitmap caching parameters and usage")
- +{
- + if (dc_optional_string_either("help", "--help")) {
- + dc_printf("Usage: BmpMan [arg]\nWhere arg can be any of the following:\n");
- + dc_printf("\tflush Unloads all bitmaps.\n");
- + dc_printf("\tram [x] Sets max mem usage to x MB. (Set to 0 to have no limit.)\n");
- + dc_printf("\t? Displays status of Bitmap manager.\n");
- + return;
- + }
- +
- + if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
- + dc_printf("Total RAM usage: %d bytes\n", bm_texture_ram);
- +
- + if (Bm_max_ram > 1024 * 1024) {
- + dc_printf("\tMax RAM allowed: %.1f MB\n", i2fl(Bm_max_ram) / (1024.0f*1024.0f));
- + }
- + else if (Bm_max_ram > 1024) {
- + dc_printf("\tMax RAM allowed: %.1f KB\n", i2fl(Bm_max_ram) / (1024.0f));
- + }
- + else if (Bm_max_ram > 0) {
- + dc_printf("\tMax RAM allowed: %d bytes\n", Bm_max_ram);
- + }
- + else {
- + dc_printf("\tNo RAM limit\n");
- + }
- + return;
- + }
- +
- +
- + if (dc_optional_string("flush")) {
- + dc_printf("Total RAM usage before flush: %d bytes\n", bm_texture_ram);
- + int i;
- + for (i = 0; i < MAX_BITMAPS; i++) {
- + if (bm_bitmaps[i].type != BM_TYPE_NONE) {
- + bm_free_data(i);
- + }
- + }
- + dc_printf("Total RAM after flush: %d bytes\n", bm_texture_ram);
- + }
- + else if (dc_optional_string("ram")) {
- + dc_stuff_int(&Bm_max_ram);
- +
- + if (Bm_max_ram > 0) {
- + dc_printf("BmpMan limited to %i, MB's\n", Bm_max_ram);
- + Bm_max_ram *= 1024 * 1024;
- + }
- + else if (Bm_max_ram == 0) {
- + dc_printf("!!BmpMan memory is unlimited!!\n");
- + }
- + else {
- + dc_printf("Illegal value. Must be non-negative.");
- + }
- + }
- + else {
- + dc_printf("<BmpMan> No argument given\n");
- + }
- +}
- +
- +/**
- +* Marks a texture as being used for this level
- +*/
- +void bm_page_in_texture(int bitmapnum, int nframes)
- +{
- + int i;
- + int n = bitmapnum % MAX_BITMAPS;
- +
- + if (bitmapnum < 0)
- + return;
- +
- + Assertion((bm_bitmaps[n].handle == bitmapnum), "bitmapnum = %i, n = %i, bm_bitmaps[n].handle = %i", bitmapnum, n, bm_bitmaps[n].handle);
- +
- + if (nframes <= 0) {
- + if ((bm_bitmaps[n].type == BM_TYPE_ANI) || (bm_bitmaps[n].type == BM_TYPE_EFF))
- + nframes = bm_bitmaps[n].info.ani.num_frames;
- + else
- + nframes = 1;
- + }
- +
- + for (i = 0; i < nframes;i++) {
- + bm_bitmaps[n + i].preloaded = 1;
- +
- + bm_bitmaps[n + i].preload_count++;
- +
- + bm_bitmaps[n + i].used_flags = BMP_TEX_OTHER;
- +
- + //check if its compressed
- + switch (bm_bitmaps[n + i].comp_type)
- + {
- + case BM_TYPE_NONE:
- + continue;
- +
- + case BM_TYPE_DXT1:
- + bm_bitmaps[n + i].used_flags = BMP_TEX_DXT1;
- + continue;
- +
- + case BM_TYPE_DXT3:
- + bm_bitmaps[n + i].used_flags = BMP_TEX_DXT3;
- + continue;
- +
- + case BM_TYPE_DXT5:
- + bm_bitmaps[n + i].used_flags = BMP_TEX_DXT5;
- + continue;
- +
- + case BM_TYPE_CUBEMAP_DXT1:
- + case BM_TYPE_CUBEMAP_DXT3:
- + case BM_TYPE_CUBEMAP_DXT5:
- + bm_bitmaps[n + i].used_flags = BMP_TEX_CUBEMAP;
- + continue;
- + }
- + }
- +}
- +
- +/**
- +* Marks a texture as being a transparent texture used for this level
- +*
- +* @param bitmapnum Index into ::bm_bitmaps ( index returned from bm_load() or bm_create() )
- +* @param nframes Animation number of frames
- +*/
- +void bm_page_in_xparent_texture(int bitmapnum, int nframes)
- +{
- + int i;
- + int n = bitmapnum % MAX_BITMAPS;
- +
- + if (n == -1)
- + return;
- +
- + Assert(bm_bitmaps[n].handle == bitmapnum);
- +
- + for (i = 0; i < nframes; i++) {
- + bm_bitmaps[n + i].preloaded = 3;
- - bm_bitmaps[n].palette_checksum = 0;
- - bm_bitmaps[n].handle = bm_get_next_handle() * MAX_BITMAPS + n;
- - bm_bitmaps[n].last_used = -1;
- + bm_bitmaps[n + i].preload_count++;
- - if (bm_bitmaps[n].mem_taken) {
- - bm_bitmaps[n].bm.data = (ptr_u)bm_malloc(n, bm_bitmaps[n].mem_taken);
- - }
- + bm_bitmaps[n + i].used_flags = BMP_TEX_XPARENT;
- - return bm_bitmaps[n].handle;
- -}
- + //check if its compressed
- + switch (bm_bitmaps[n + i].comp_type)
- + {
- + case BM_TYPE_NONE:
- + continue;
- -void *bm_malloc(int n, int size) {
- - Assert((n >= 0) && (n < MAX_BITMAPS));
- + case BM_TYPE_DXT1:
- + bm_bitmaps[n + i].used_flags = BMP_TEX_DXT1;
- + continue;
- - if (size <= 0)
- - return NULL;
- + case BM_TYPE_DXT3:
- + bm_bitmaps[n + i].used_flags = BMP_TEX_DXT3;
- + continue;
- -#ifdef BMPMAN_NDEBUG
- - Assert(bm_bitmaps[n].data_size == 0);
- - bm_bitmaps[n].data_size += size;
- - bm_texture_ram += size;
- -#endif
- + case BM_TYPE_DXT5:
- + bm_bitmaps[n + i].used_flags = BMP_TEX_DXT5;
- + continue;
- - return vm_malloc(size);
- + case BM_TYPE_CUBEMAP_DXT1:
- + case BM_TYPE_CUBEMAP_DXT3:
- + case BM_TYPE_CUBEMAP_DXT5:
- + bm_bitmaps[n + i].used_flags = BMP_TEX_CUBEMAP;
- + continue;
- + }
- + }
- }
- -void bm_page_in_aabitmap(int bitmapnum, int nframes) {
- +/**
- +* Marks an aabitmap as being used for this level
- +*
- +* @param bitmapnum Index into ::bm_bitmaps ( index returned from bm_load() or bm_create() )
- +* @param nframes Animation number of frames
- +*/
- +void bm_page_in_aabitmap(int bitmapnum, int nframes)
- +{
- int i;
- int n = bitmapnum % MAX_BITMAPS;
- @@ -2046,7 +2265,7 @@ void bm_page_in_aabitmap(int bitmapnum, int nframes) {
- Assert(bm_bitmaps[n].handle == bitmapnum);
- - for (i = 0; i<nframes; i++) {
- + for (i = 0; i<nframes;i++) {
- bm_bitmaps[n + i].preloaded = 2;
- bm_bitmaps[n + i].preload_count++;
- @@ -2055,7 +2274,11 @@ void bm_page_in_aabitmap(int bitmapnum, int nframes) {
- }
- }
- -void bm_page_in_start() {
- +/**
- +* Tell the bitmap manager to start keeping track of what bitmaps are used where.
- +*/
- +void bm_page_in_start()
- +{
- int i;
- Bm_paging = 1;
- @@ -2076,7 +2299,10 @@ void bm_page_in_start() {
- gr_bm_page_in_start();
- }
- -void bm_page_in_stop() {
- +extern void multi_ping_send_all();
- +
- +void bm_page_in_stop()
- +{
- int i;
- #ifndef NDEBUG
- @@ -2098,11 +2324,10 @@ void bm_page_in_stop() {
- mprintf(("Out of VRAM. Done preloading.\n"));
- bm_preloading = 0;
- }
- - } else {
- + }
- + else {
- bm_lock(bm_bitmaps[i].handle, (bm_bitmaps[i].used_flags == BMP_AABITMAP) ? 8 : 16, bm_bitmaps[i].used_flags);
- - if (bm_bitmaps[i].ref_count >= 1) {
- - bm_unlock( bm_bitmaps[i].handle );
- - }
- + bm_unlock(bm_bitmaps[i].handle);
- }
- n++;
- @@ -2122,7 +2347,8 @@ void bm_page_in_stop() {
- game_busy();
- #endif
- }
- - } else {
- + }
- + else {
- bm_unload_fast(bm_bitmaps[i].handle);
- }
- }
- @@ -2145,355 +2371,515 @@ void bm_page_in_stop() {
- Bm_paging = 0;
- }
- -void bm_page_in_texture(int bitmapnum, int nframes) {
- - int i;
- - int n = bitmapnum % MAX_BITMAPS;
- +/**
- +* For unloading bitmaps while a mission is going
- +*/
- +int bm_page_out(int bitmap_id)
- +{
- + int n = bitmap_id % MAX_BITMAPS;
- - if (bitmapnum < 0)
- + Assert(n >= 0 && n < MAX_BITMAPS);
- +
- + // in case it's already been released
- + if (bm_bitmaps[n].type == BM_TYPE_NONE)
- + return 0;
- +
- + Assert(bm_bitmaps[n].handle == bitmap_id); // INVALID BITMAP HANDLE
- +
- + // it's possible to hit < 0 here when model_page_out_textures() is called from
- + // anywhere other than in a mission
- + if (bm_bitmaps[n].preload_count > 0) {
- + nprintf(("BmpMan", "PAGE-OUT: %s - preload_count remaining: %d\n", bm_bitmaps[n].filename, bm_bitmaps[n].preload_count));
- +
- + // lets decrease it for next time around
- + bm_bitmaps[n].preload_count--;
- +
- + return 0;
- + }
- +
- + return (bm_unload(bitmap_id) == 1);
- +}
- +
- +int bm_get_cache_slot(int bitmap_id, int separate_ani_frames)
- +{
- + int n = bitmap_id % MAX_BITMAPS;
- +
- + Assert(n >= 0);
- + Assert(bm_bitmaps[n].handle == bitmap_id); // INVALID BITMAP HANDLE
- +
- + bitmap_entry *be = &bm_bitmaps[n];
- +
- + if ((!separate_ani_frames) && ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF))) {
- + return be->info.ani.first_frame;
- + }
- +
- + return n;
- +
- +}
- +
- +void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
- +void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
- +
- +void bm_set_components_argb_16_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
- +{
- + if (*av == 0) {
- + *((unsigned short*)pixel) = (unsigned short)Gr_current_green->mask;
- return;
- + }
- - Assertion((bm_bitmaps[n].handle == bitmapnum), "bitmapnum = %i, n = %i, bm_bitmaps[n].handle = %i", bitmapnum, n, bm_bitmaps[n].handle);
- + *((unsigned short*)pixel) = (unsigned short)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
- + *((unsigned short*)pixel) |= (unsigned short)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
- + *((unsigned short*)pixel) |= (unsigned short)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
- +}
- - if (nframes <= 0) {
- - if ((bm_bitmaps[n].type == BM_TYPE_ANI) || (bm_bitmaps[n].type == BM_TYPE_EFF))
- - nframes = bm_bitmaps[n].info.ani.num_frames;
- - else
- - nframes = 1;
- +void bm_set_components_argb_32_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
- +{
- + if (*av == 0) {
- + *((unsigned int*)pixel) = (unsigned int)Gr_current_green->mask;
- + return;
- }
- - for (i = 0; i < nframes; i++) {
- - bm_bitmaps[n + i].preloaded = 1;
- + *((unsigned int*)pixel) = (unsigned int)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
- + *((unsigned int*)pixel) |= (unsigned int)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
- + *((unsigned int*)pixel) |= (unsigned int)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
- +}
- - bm_bitmaps[n + i].preload_count++;
- +void bm_set_components_argb_16_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
- +{
- + if (*av == 0) {
- + *((unsigned short*)pixel) = 0;
- + return;
- + }
- - bm_bitmaps[n + i].used_flags = BMP_TEX_OTHER;
- + *((unsigned short*)pixel) = (unsigned short)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
- + *((unsigned short*)pixel) |= (unsigned short)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
- + *((unsigned short*)pixel) |= (unsigned short)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
- + *((unsigned short*)pixel) |= (unsigned short)(Gr_current_alpha->mask);
- +}
- - //check if its compressed
- - switch (bm_bitmaps[n + i].comp_type) {
- - case BM_TYPE_NONE:
- - continue;
- +void bm_set_components_argb_32_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av)
- +{
- + if (*av == 0) {
- + *((unsigned int*)pixel) = 0;
- + return;
- + }
- - case BM_TYPE_DXT1:
- - bm_bitmaps[n + i].used_flags = BMP_TEX_DXT1;
- - continue;
- + *((unsigned int*)pixel) = (unsigned int)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
- + *((unsigned int*)pixel) |= (unsigned int)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
- + *((unsigned int*)pixel) |= (unsigned int)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
- + *((unsigned int*)pixel) |= (unsigned int)(Gr_current_alpha->mask);
- +}
- - case BM_TYPE_DXT3:
- - bm_bitmaps[n + i].used_flags = BMP_TEX_DXT3;
- - continue;
- +/**
- +* For selecting pixel formats
- +*/
- +void BM_SELECT_SCREEN_FORMAT()
- +{
- + Gr_current_red = &Gr_red;
- + Gr_current_green = &Gr_green;
- + Gr_current_blue = &Gr_blue;
- + Gr_current_alpha = &Gr_alpha;
- - case BM_TYPE_DXT5:
- - bm_bitmaps[n + i].used_flags = BMP_TEX_DXT5;
- - continue;
- + // setup pointers
- + bm_set_components_32 = bm_set_components_argb_32_screen;
- + // should always assume that 16-bit is the default request
- + bm_set_components = bm_set_components_argb_16_screen;
- +}
- - case BM_TYPE_CUBEMAP_DXT1:
- - case BM_TYPE_CUBEMAP_DXT3:
- - case BM_TYPE_CUBEMAP_DXT5:
- - bm_bitmaps[n + i].used_flags = BMP_TEX_CUBEMAP;
- - continue;
- +void BM_SELECT_TEX_FORMAT()
- +{
- + Gr_current_red = &Gr_t_red;
- + Gr_current_green = &Gr_t_green;
- + Gr_current_blue = &Gr_t_blue;
- + Gr_current_alpha = &Gr_t_alpha;
- - default:
- - continue;
- + // setup pointers
- + bm_set_components_32 = bm_set_components_argb_32_tex;
- + // should always assume that 16-bit is the default request
- + bm_set_components = bm_set_components_argb_16_tex;
- +}
- +
- +void BM_SELECT_ALPHA_TEX_FORMAT()
- +{
- + Gr_current_red = &Gr_ta_red;
- + Gr_current_green = &Gr_ta_green;
- + Gr_current_blue = &Gr_ta_blue;
- + Gr_current_alpha = &Gr_ta_alpha;
- +
- + // setup pointers
- + bm_set_components_32 = bm_set_components_argb_32_tex;
- + // should always assume that 16-bit is the default request
- + bm_set_components = bm_set_components_argb_16_tex;
- +}
- +
- +/**
- +* Get the rgba components of a pixel, any of the parameters can be NULL
- +*/
- +void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a)
- +{
- + int bit_32 = 0;
- +
- + if ((gr_screen.bits_per_pixel == 32) && (Gr_current_red == &Gr_red)) {
- + bit_32 = 1;
- + }
- +
- + if (r != NULL) {
- + if (bit_32) {
- + *r = ubyte(((*((unsigned int*)pixel) & Gr_current_red->mask) >> Gr_current_red->shift)*Gr_current_red->scale);
- + }
- + else {
- + *r = ubyte(((((unsigned short*)pixel)[0] & Gr_current_red->mask) >> Gr_current_red->shift)*Gr_current_red->scale);
- + }
- + }
- +
- + if (g != NULL) {
- + if (bit_32) {
- + *g = ubyte(((*((unsigned int*)pixel) & Gr_current_green->mask) >> Gr_current_green->shift)*Gr_current_green->scale);
- + }
- + else {
- + *g = ubyte(((((unsigned short*)pixel)[0] & Gr_current_green->mask) >> Gr_current_green->shift)*Gr_current_green->scale);
- + }
- + }
- +
- + if (b != NULL) {
- + if (bit_32) {
- + *b = ubyte(((*((unsigned int*)pixel) & Gr_current_blue->mask) >> Gr_current_blue->shift)*Gr_current_blue->scale);
- + }
- + else {
- + *b = ubyte(((((unsigned short*)pixel)[0] & Gr_current_blue->mask) >> Gr_current_blue->shift)*Gr_current_blue->scale);
- + }
- + }
- +
- + // get the alpha value
- + if (a != NULL) {
- + *a = 1;
- +
- + Assert(!bit_32);
- + if (!(((unsigned short*)pixel)[0] & 0x8000)) {
- + *a = 0;
- }
- }
- }
- -void bm_page_in_xparent_texture(int bitmapnum, int nframes) {
- - int i;
- +/**
- +* Get filename
- +*/
- +void bm_get_filename(int bitmapnum, char *filename)
- +{
- + if (!bm_is_valid(bitmapnum))
- + {
- + strcpy(filename, "");
- + return;
- + }
- +
- int n = bitmapnum % MAX_BITMAPS;
- - if (n == -1)
- - return;
- + Assert(n >= 0);
- - Assert(bm_bitmaps[n].handle == bitmapnum);
- + // return filename
- + strcpy(filename, bm_bitmaps[n].filename);
- +}
- +
- +/**
- +* Needed only for compressed bitmaps
- +*/
- +int bm_is_compressed(int num)
- +{
- + int n = num % MAX_BITMAPS;
- + ubyte type = BM_TYPE_NONE;
- +
- + //duh
- + if (!Use_compressed_textures)
- + return 0;
- - for (i = 0; i < nframes; i++) {
- - bm_bitmaps[n + i].preloaded = 3;
- + Assert(n >= 0);
- + Assert(num == bm_bitmaps[n].handle);
- - bm_bitmaps[n + i].preload_count++;
- + type = bm_bitmaps[n].comp_type;
- - bm_bitmaps[n + i].used_flags = BMP_TEX_XPARENT;
- + switch (type) {
- + case BM_TYPE_NONE:
- + case BM_TYPE_DDS:
- + return 0;
- - //check if its compressed
- - switch (bm_bitmaps[n + i].comp_type) {
- - case BM_TYPE_NONE:
- - continue;
- + case BM_TYPE_DXT1:
- + return DDS_DXT1;
- - case BM_TYPE_DXT1:
- - bm_bitmaps[n + i].used_flags = BMP_TEX_DXT1;
- - continue;
- + case BM_TYPE_DXT3:
- + return DDS_DXT3;
- - case BM_TYPE_DXT3:
- - bm_bitmaps[n + i].used_flags = BMP_TEX_DXT3;
- - continue;
- + case BM_TYPE_DXT5:
- + return DDS_DXT5;
- - case BM_TYPE_DXT5:
- - bm_bitmaps[n + i].used_flags = BMP_TEX_DXT5;
- - continue;
- + case BM_TYPE_CUBEMAP_DXT1:
- + return DDS_CUBEMAP_DXT1;
- - case BM_TYPE_CUBEMAP_DXT1:
- - case BM_TYPE_CUBEMAP_DXT3:
- - case BM_TYPE_CUBEMAP_DXT5:
- - bm_bitmaps[n + i].used_flags = BMP_TEX_CUBEMAP;
- - continue;
- + case BM_TYPE_CUBEMAP_DXT3:
- + return DDS_CUBEMAP_DXT3;
- - default:
- - continue;
- - }
- + case BM_TYPE_CUBEMAP_DXT5:
- + return DDS_CUBEMAP_DXT5;
- }
- +
- + return 0;
- }
- -bool bm_page_out(int handle) {
- +int bm_has_alpha_channel(int handle)
- +{
- int n = handle % MAX_BITMAPS;
- Assert(n >= 0);
- Assert(handle == bm_bitmaps[n].handle);
- - // in case it's already been released
- - if (bm_bitmaps[n].type == BM_TYPE_NONE)
- + // assume that PCX never has a real alpha channel (it may be 32-bit, but without any alpha)
- + if (bm_bitmaps[n].type == BM_TYPE_PCX)
- return 0;
- - // it's possible to hit < 0 here when model_page_out_textures() is
- - // called from anywhere other than in a mission
- - if (bm_bitmaps[n].preload_count > 0) {
- - nprintf(("BmpMan",
- - "PAGE-OUT: %s - preload_count remaining: %d\n",
- - bm_bitmaps[n].filename,
- - bm_bitmaps[n].preload_count));
- -
- - // lets decrease it for next time around
- - bm_bitmaps[n].preload_count--;
- + return (bm_bitmaps[n].bm.true_bpp == 32);
- +}
- - return 0;
- - }
- +/**
- +* Purpose for this is to return the correct TCACHE_TYPE for compressed graphics,
- +* uncompressed graphics are assumed to be of type NORMAL.
- +*
- +* The only other real format to check for is TCACHE_TYPE_SECTIONED - taylor
- +*/
- +int bm_get_tcache_type(int num)
- +{
- + if (bm_is_compressed(num))
- + return TCACHE_TYPE_COMPRESSED;
- - return (bm_unload(handle) == 1);
- + return TCACHE_TYPE_NORMAL;
- }
- -void bm_print_bitmaps() {
- -#ifdef BMPMAN_NDEBUG
- - int i;
- +int bm_get_size(int num)
- +{
- + int n = num % MAX_BITMAPS;
- - for (i = 0; i<MAX_BITMAPS; i++) {
- - if (bm_bitmaps[i].type != BM_TYPE_NONE) {
- - if (bm_bitmaps[i].data_size) {
- - 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));
- - } else {
- - nprintf(("BMP DEBUG", "BMPMAN = num: %d, name: %s, handle: %d\n", i, bm_bitmaps[i].filename, bm_bitmaps[i].handle));
- - }
- - }
- - }
- - nprintf(("BMP DEBUG", "BMPMAN = LOCKED memory usage: %.3fM\n", ((float)bm_texture_ram / 1024.0f) / 1024.0f));
- -#endif
- + Assert(n >= 0);
- + Assert(num == bm_bitmaps[n].handle);
- +
- + return bm_bitmaps[n].mem_taken;
- }
- -int bm_release(int handle, int clear_render_targets) {
- - Assert(handle >= 0);
- +int bm_get_num_mipmaps(int num)
- +{
- + int n = num % MAX_BITMAPS;
- - bitmap_entry *be;
- + Assert(n >= 0);
- + Assert(num == bm_bitmaps[n].handle);
- - int n = handle % MAX_BITMAPS;
- + if (bm_bitmaps[n].num_mipmaps == 0)
- + return 1;
- - Assert((n >= 0) && (n < MAX_BITMAPS));
- - be = &bm_bitmaps[n];
- + return bm_bitmaps[n].num_mipmaps;
- +}
- - if (be->type == BM_TYPE_NONE) {
- - return 0; // Already been released?
- - }
- +/**
- +* Convert an 8-bit (256 color) image to a 24-bit BGR image sending new bitmap data to "out_data"
- +*/
- +int bm_convert_color_index_to_BGR(int num, ubyte **out_data)
- +{
- + int n = num % MAX_BITMAPS;
- + bitmap_entry *be;
- + bitmap *bmp;
- + ubyte *datap, *bgr_data = NULL, *palette = NULL;
- + char filename[MAX_FILENAME_LEN];
- + int i, j, bpp = 0, size = 0;
- + int index = 0, mult = 3;
- - Assertion(be->handle == handle, "Invalid bitmap handle number %d (expected %d) for %s passed to bm_release()\n", be->handle, handle, be->filename);
- + Assert(out_data != NULL);
- + Assert(n >= 0);
- + Assert(num == bm_bitmaps[n].handle);
- - if (!clear_render_targets && ((be->type == BM_TYPE_RENDER_TARGET_STATIC) || (be->type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
- - nprintf(("BmpMan", "Tried to release a render target!\n"));
- - return 0;
- - }
- + if (num != bm_bitmaps[n].handle)
- + return 1;
- - // If it is locked, cannot free it.
- - if (be->ref_count != 0) {
- - nprintf(("BmpMan", "Tried to release %s that has a lock count of %d.. not releasing\n", be->filename, be->ref_count));
- - return 0;
- + be = &bm_bitmaps[n];
- + bmp = &be->bm;
- +
- + if ((bmp->bpp != 8) || !(bmp->data) || ((be->type != BM_TYPE_DDS) && (be->type != BM_TYPE_PCX)))
- + {
- + return 1;
- }
- - // kind of like ref_count except it gets around the lock/unlock usage problem
- - // this gets set for each bm_load() call so we can make sure and not unload it
- - // from memory, even if we *can*, until it's really not needed anymore
- - if (be->load_count > 0)
- - be->load_count--;
- + // it's up to the calling function to free() this but not to malloc() it!!
- + bgr_data = (ubyte*)vm_malloc_q(bmp->w * bmp->h * 3);
- - if (be->load_count != 0) {
- - nprintf(("BmpMan", "Tried to release %s that has a load count of %d.. not releasing\n", be->filename, be->load_count + 1));
- - return 0;
- - }
- + ubyte *in_data = (ubyte*)bmp->data;
- - if (be->type != BM_TYPE_USER) {
- - nprintf(("BmpMan", "Releasing bitmap %s in slot %i with handle %i\n", be->filename, n, handle));
- - }
- + if (bgr_data == NULL)
- + return 1;
- - // be sure that all frames of an ani are unloaded - taylor
- - if ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF)) {
- - int i, first = be->info.ani.first_frame, total = bm_bitmaps[first].info.ani.num_frames;
- + memset(bgr_data, 0, bmp->w * bmp->h * 3);
- - for (i = 0; i < total; i++) {
- - bm_free_data(first + i, true); // clears flags, bbp, data, etc
- + palette = new ubyte[1024]; // 256*4, largest size we should have to process
- + Assert(palette != NULL);
- - memset(&bm_bitmaps[first + i], 0, sizeof(bitmap_entry));
- + // make sure we are using the correct filename in the case of an EFF.
- + // this will populate filename[] whether it's EFF or not
- + EFF_FILENAME_CHECK;
- - bm_bitmaps[first + i].type = BM_TYPE_NONE;
- - bm_bitmaps[first + i].comp_type = BM_TYPE_NONE;
- - bm_bitmaps[first + i].dir_type = CF_TYPE_ANY;
- - // Fill in bogus structures!
- + if (be->type == BM_TYPE_PCX) {
- + pcx_read_header(filename, NULL, NULL, NULL, &bpp, palette);
- + mult = 3; // PCX has RGB for 256 entries
- + }
- + else if (be->type == BM_TYPE_DDS) {
- + dds_read_header(filename, NULL, NULL, NULL, &bpp, NULL, NULL, &size, palette);
- + mult = 4; // DDS has RGBX for 256 entries, 'X' being an alpha setting that we don't need
- + }
- + else {
- + // we really shouldn't be here at this point but give it another check anyway
- + delete[] palette;
- + vm_free(bgr_data);
- + return 1;
- + }
- - // For debugging:
- - strcpy_s(bm_bitmaps[first + i].filename, "IVE_BEEN_RELEASED!");
- - bm_bitmaps[first + i].signature = 0xDEADBEEF; // a unique signature identifying the data
- - bm_bitmaps[first + i].palette_checksum = 0xDEADBEEF; // checksum used to be sure bitmap is in current palette
- + Assert(bpp == 8);
- - // bookeeping
- - bm_bitmaps[first + i].ref_count = -1; // Number of locks on bitmap. Can't unload unless ref_count is 0.
- + // we can only accept 8bits obviously, but this is actually a read error check
- + if (bpp != 8) {
- + delete[] palette;
- + vm_free(bgr_data);
- + return 1;
- + }
- - // Stuff needed for animations
- - bm_bitmaps[first + i].info.ani.first_frame = -1;
- + datap = bgr_data;
- - bm_bitmaps[first + i].handle = -1;
- + for (i = 0; i < bmp->h; i++) {
- + for (j = 0; j < bmp->w; j++) {
- + index = *in_data++;
- + *datap++ = palette[index * mult + 2];
- + *datap++ = palette[index * mult + 1];
- + *datap++ = palette[index * mult];
- }
- - } else {
- - bm_free_data(n, true); // clears flags, bbp, data, etc
- -
- - memset(&bm_bitmaps[n], 0, sizeof(bitmap_entry));
- + }
- - bm_bitmaps[n].type = BM_TYPE_NONE;
- - bm_bitmaps[n].comp_type = BM_TYPE_NONE;
- - bm_bitmaps[n].dir_type = CF_TYPE_ANY;
- - // Fill in bogus structures!
- + *out_data = bgr_data;
- - // For debugging:
- - strcpy_s(bm_bitmaps[n].filename, "IVE_BEEN_RELEASED!");
- - bm_bitmaps[n].signature = 0xDEADBEEF; // a unique signature identifying the data
- - bm_bitmaps[n].palette_checksum = 0xDEADBEEF; // checksum used to be sure bitmap is in current palette
- + delete[] palette;
- - // bookeeping
- - bm_bitmaps[n].ref_count = -1; // Number of locks on bitmap. Can't unload unless ref_count is 0.
- + // no errors
- + return 0;
- +}
- - // Stuff needed for animations
- - bm_bitmaps[n].info.ani.first_frame = -1;
- +/**
- +* List of all bitmaps loaded, but not necessarily in memory
- +* used to debug bmpman after a mission load
- +*/
- +void bm_print_bitmaps()
- +{
- +#ifdef BMPMAN_NDEBUG
- + int i;
- - bm_bitmaps[n].handle = -1;
- + for (i = 0; i<MAX_BITMAPS; i++) {
- + if (bm_bitmaps[i].type != BM_TYPE_NONE) {
- + if (bm_bitmaps[i].data_size) {
- + 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));
- + }
- + else {
- + nprintf(("BMP DEBUG", "BMPMAN = num: %d, name: %s, handle: %d\n", i, bm_bitmaps[i].filename, bm_bitmaps[i].handle));
- + }
- + }
- }
- -
- - return 1;
- + nprintf(("BMP DEBUG", "BMPMAN = LOCKED memory usage: %.3fM\n", ((float)bm_texture_ram / 1024.0f) / 1024.0f));
- +#endif
- }
- -int bm_reload(int bitmap_handle, const char* filename) {
- +// this will create a render target as close to the desired resolution as possable of the following base types:
- +// - BMP_FLAG_RENDER_TARGET_STATIC
- +// static render targets are ones that you intend to draw to once or not very often in game
- +// - BMP_FLAG_RENDER_TARGET_DYNAMIC
- +// dynamic render targets are ones that you will be drawing to all the time (like once per frame)
- +int bm_make_render_target(int width, int height, int flags)
- +{
- + int i, n;
- + int mm_lvl = 0;
- + // final w and h may be different from passed width and height
- + int w = width, h = height;
- + ubyte bpp = 32;
- + int size = 0;
- +
- if (!bm_inited)
- bm_init();
- - // if no file was passed then get out now
- - if ((filename == NULL) || (strlen(filename) <= 0))
- - return -1;
- -
- - int bitmapnum = bitmap_handle % MAX_BITMAPS;
- + // Find an open slot (starting from the end)
- + for (n = -1, i = MAX_BITMAPS - 1; i >= 0; i--) {
- + if (bm_bitmaps[i].type == BM_TYPE_NONE) {
- + n = i;
- + break;
- + }
- + }
- - if (bm_bitmaps[bitmapnum].type == BM_TYPE_NONE)
- + // Out of bitmap slots
- + if (n == -1)
- return -1;
- - if (bm_bitmaps[bitmapnum].ref_count) {
- - 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));
- + if (!gr_bm_make_render_target(n, &w, &h, &bpp, &mm_lvl, flags))
- return -1;
- - }
- -
- - strcpy_s(bm_bitmaps[bitmapnum].filename, filename);
- - return bitmap_handle;
- -}
- -
- -void BM_SELECT_ALPHA_TEX_FORMAT() {
- - Gr_current_red = &Gr_ta_red;
- - Gr_current_green = &Gr_ta_green;
- - Gr_current_blue = &Gr_ta_blue;
- - Gr_current_alpha = &Gr_ta_alpha;
- -
- - // setup pointers
- - bm_set_components_32 = bm_set_components_argb_32_tex;
- - // should always assume that 16-bit is the default request
- - bm_set_components = bm_set_components_argb_16_tex;
- -}
- -void BM_SELECT_SCREEN_FORMAT() {
- - Gr_current_red = &Gr_red;
- - Gr_current_green = &Gr_green;
- - Gr_current_blue = &Gr_blue;
- - Gr_current_alpha = &Gr_alpha;
- -
- - // setup pointers
- - bm_set_components_32 = bm_set_components_argb_32_screen;
- - // should always assume that 16-bit is the default request
- - bm_set_components = bm_set_components_argb_16_screen;
- -}
- -
- -void BM_SELECT_TEX_FORMAT() {
- - Gr_current_red = &Gr_t_red;
- - Gr_current_green = &Gr_t_green;
- - Gr_current_blue = &Gr_t_blue;
- - Gr_current_alpha = &Gr_t_alpha;
- + Assert(mm_lvl > 0);
- - // setup pointers
- - bm_set_components_32 = bm_set_components_argb_32_tex;
- - // should always assume that 16-bit is the default request
- - bm_set_components = bm_set_components_argb_16_tex;
- -}
- + if (flags & BMP_FLAG_RENDER_TARGET_STATIC) {
- + // data size
- + size = (w * h * (bpp >> 3));
- -void bm_set_components_argb_16_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av) {
- - if (*av == 0) {
- - *((unsigned short*)pixel) = (unsigned short)Gr_current_green->mask;
- - return;
- + if (mm_lvl > 1) {
- + // include size of all mipmap levels (there should be a full chain)
- + size += (size / 3) - 1;
- + }
- +
- + // make sure to count all faces if a cubemap
- + if (flags & BMP_FLAG_CUBEMAP) {
- + size *= 6;
- + }
- }
- - *((unsigned short*)pixel) = (unsigned short)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
- - *((unsigned short*)pixel) |= (unsigned short)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
- - *((unsigned short*)pixel) |= (unsigned short)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
- -}
- + // ensure fields are cleared out from previous bitmap
- + memset(&bm_bitmaps[n], 0, sizeof(bitmap_entry));
- -void bm_set_components_argb_16_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av) {
- - if (*av == 0) {
- - *((unsigned short*)pixel) = 0;
- - return;
- - }
- + bm_bitmaps[n].type = (flags & BMP_FLAG_RENDER_TARGET_STATIC) ? BM_TYPE_RENDER_TARGET_STATIC : BM_TYPE_RENDER_TARGET_DYNAMIC;
- + bm_bitmaps[n].signature = Bm_next_signature++;
- + sprintf(bm_bitmaps[n].filename, "RT_%dx%d+%d", w, h, bpp);
- + bm_bitmaps[n].bm.w = (short)w;
- + bm_bitmaps[n].bm.h = (short)h;
- + bm_bitmaps[n].bm.rowsize = (short)w;
- + bm_bitmaps[n].bm.bpp = (ubyte)bpp;
- + bm_bitmaps[n].bm.true_bpp = (ubyte)bpp;
- + bm_bitmaps[n].bm.flags = (ubyte)flags;
- + bm_bitmaps[n].bm.data = 0;
- + bm_bitmaps[n].bm.palette = NULL;
- + bm_bitmaps[n].num_mipmaps = mm_lvl;
- + bm_bitmaps[n].mem_taken = size;
- + bm_bitmaps[n].dir_type = CF_TYPE_ANY;
- - *((unsigned short*)pixel) = (unsigned short)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
- - *((unsigned short*)pixel) |= (unsigned short)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
- - *((unsigned short*)pixel) |= (unsigned short)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
- - *((unsigned short*)pixel) |= (unsigned short)(Gr_current_alpha->mask);
- -}
- + bm_bitmaps[n].palette_checksum = 0;
- + bm_bitmaps[n].handle = bm_get_next_handle() * MAX_BITMAPS + n;
- + bm_bitmaps[n].last_used = -1;
- -void bm_set_components_argb_32_screen(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av) {
- - if (*av == 0) {
- - *((unsigned int*)pixel) = (unsigned int)Gr_current_green->mask;
- - return;
- + if (bm_bitmaps[n].mem_taken) {
- + bm_bitmaps[n].bm.data = (ptr_u)bm_malloc(n, bm_bitmaps[n].mem_taken);
- }
- - *((unsigned int*)pixel) = (unsigned int)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
- - *((unsigned int*)pixel) |= (unsigned int)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
- - *((unsigned int*)pixel) |= (unsigned int)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
- + return bm_bitmaps[n].handle;
- }
- -void bm_set_components_argb_32_tex(ubyte *pixel, ubyte *rv, ubyte *gv, ubyte *bv, ubyte *av) {
- - if (*av == 0) {
- - *((unsigned int*)pixel) = 0;
- - return;
- - }
- +int bm_is_render_target(int bitmap_id)
- +{
- + int n = bitmap_id % MAX_BITMAPS;
- - *((unsigned int*)pixel) = (unsigned int)(((int)*rv / Gr_current_red->scale) << Gr_current_red->shift);
- - *((unsigned int*)pixel) |= (unsigned int)(((int)*gv / Gr_current_green->scale) << Gr_current_green->shift);
- - *((unsigned int*)pixel) |= (unsigned int)(((int)*bv / Gr_current_blue->scale) << Gr_current_blue->shift);
- - *((unsigned int*)pixel) |= (unsigned int)(Gr_current_alpha->mask);
- -}
- + Assert(n >= 0);
- + Assert(bitmap_id == bm_bitmaps[n].handle);
- -void bm_set_low_mem(int mode) {
- - Assert((mode >= 0) && (mode <= 2));
- + if (!((bm_bitmaps[n].type == BM_TYPE_RENDER_TARGET_STATIC) || (bm_bitmaps[n].type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
- + return 0;
- + }
- - CLAMP(mode, 0, 2);
- - Bm_low_mem = mode;
- + return bm_bitmaps[n].type;
- }
- -bool bm_set_render_target(int handle, int face) {
- +int bm_set_render_target(int handle, int face)
- +{
- int n = handle % MAX_BITMAPS;
- if (n >= 0) {
- @@ -2502,7 +2888,7 @@ bool bm_set_render_target(int handle, int face) {
- if ((bm_bitmaps[n].type != BM_TYPE_RENDER_TARGET_STATIC) && (bm_bitmaps[n].type != BM_TYPE_RENDER_TARGET_DYNAMIC)) {
- // odds are that someone passed a normal texture created with bm_load()
- mprintf(("Trying to set invalid bitmap (slot: %i, handle: %i) as render target!\n", n, handle));
- - return false;
- + return 0;
- }
- }
- @@ -2517,12 +2903,6 @@ bool bm_set_render_target(int handle, int face) {
- gr_screen.save_max_w_unscaled_zoomed = gr_screen.max_w_unscaled_zoomed;
- gr_screen.save_max_h_unscaled_zoomed = gr_screen.max_h_unscaled_zoomed;
- -
- - gr_screen.save_center_w = gr_screen.center_w;
- - gr_screen.save_center_h = gr_screen.center_h;
- -
- - gr_screen.save_center_offset_x = gr_screen.center_offset_x;
- - gr_screen.save_center_offset_y = gr_screen.center_offset_y;
- }
- if (n < 0) {
- @@ -2534,13 +2914,8 @@ bool bm_set_render_target(int handle, int face) {
- gr_screen.max_w_unscaled_zoomed = gr_screen.save_max_w_unscaled_zoomed;
- gr_screen.max_h_unscaled_zoomed = gr_screen.save_max_h_unscaled_zoomed;
- -
- - gr_screen.center_w = gr_screen.save_center_w;
- - gr_screen.center_h = gr_screen.save_center_h;
- -
- - gr_screen.center_offset_x = gr_screen.save_center_offset_x;
- - gr_screen.center_offset_y = gr_screen.save_center_offset_y;
- - } else {
- + }
- + else {
- gr_screen.max_w = bm_bitmaps[n].bm.w;
- gr_screen.max_h = bm_bitmaps[n].bm.h;
- @@ -2549,12 +2924,6 @@ bool bm_set_render_target(int handle, int face) {
- gr_screen.max_w_unscaled_zoomed = bm_bitmaps[n].bm.w;
- gr_screen.max_h_unscaled_zoomed = bm_bitmaps[n].bm.h;
- -
- - gr_screen.center_w = bm_bitmaps[n].bm.w;
- - gr_screen.center_h = bm_bitmaps[n].bm.h;
- -
- - gr_screen.center_offset_x = 0;
- - gr_screen.center_offset_y = 0;
- }
- gr_screen.rendering_to_face = face;
- @@ -2567,184 +2936,8 @@ bool bm_set_render_target(int handle, int face) {
- opengl_setup_viewport();
- }
- - return true;
- - }
- -
- - return false;
- -}
- -
- -int bm_unload(int handle, int clear_render_targets, bool nodebug) {
- - bitmap_entry *be;
- - bitmap *bmp;
- -
- - int n = handle % MAX_BITMAPS;
- -
- - Assert((n >= 0) && (n < MAX_BITMAPS));
- - be = &bm_bitmaps[n];
- - bmp = &be->bm;
- -
- - if (!clear_render_targets && ((be->type == BM_TYPE_RENDER_TARGET_STATIC) || (be->type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
- - return -1;
- - }
- -
- - if (be->type == BM_TYPE_NONE) {
- - return -1; // Already been released
- - }
- -
- - Assert(be->handle == handle); // INVALID BITMAP HANDLE!
- -
- - // If it is locked, cannot free it.
- - if (be->ref_count != 0 && !nodebug) {
- - nprintf(("BmpMan", "Tried to unload %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
- - return 0;
- - }
- -
- - // kind of like ref_count except it gets around the lock/unlock usage problem
- - // this gets set for each bm_load() call so we can make sure and not unload it
- - // from memory, even if we *can*, until it's really not needed anymore
- - if (!Bm_ignore_load_count) {
- - if (be->load_count > 0)
- - be->load_count--;
- -
- - if (be->load_count != 0 && !nodebug) {
- - nprintf(("BmpMan", "Tried to unload %s that has a load count of %d.. not unloading\n", be->filename, be->load_count + 1));
- - return 0;
- - }
- - }
- -
- - // be sure that all frames of an ani are unloaded - taylor
- - if ((be->type == BM_TYPE_ANI) || (be->type == BM_TYPE_EFF)) {
- - int i, first = be->info.ani.first_frame;
- -
- - // for the unload all case, don't try to unload every frame of every frame
- - // all additional frames automatically get unloaded with the first one
- - if ((n > be->info.ani.first_frame) && (bm_bitmaps[first].bm.data == 0))
- - return 1;
- -
- - for (i = 0; i < bm_bitmaps[first].info.ani.num_frames; i++) {
- - if (!nodebug)
- - nprintf(("BmpMan", "Unloading %s frame %d. %dx%dx%d\n", be->filename, i, bmp->w, bmp->h, bmp->bpp));
- - bm_free_data(first + i); // clears flags, bbp, data, etc
- - }
- - } else {
- - if (!nodebug)
- - nprintf(("BmpMan", "Unloading %s. %dx%dx%d\n", be->filename, bmp->w, bmp->h, bmp->bpp));
- - bm_free_data(n); // clears flags, bbp, data, etc
- - }
- -
- - return 1;
- -}
- -
- -void bm_unload_all() {
- - int i;
- -
- - // since bm_unload_all() should only be called from game_shutdown() it should be
- - // safe to ignore load_count's and unload anyway
- - Bm_ignore_load_count = 1;
- -
- - for (i = 0; i < MAX_BITMAPS; i++) {
- - if (bm_bitmaps[i].type != BM_TYPE_NONE) {
- - bm_unload(bm_bitmaps[i].handle, 1);
- - }
- - }
- -
- - Bm_ignore_load_count = 0;
- -}
- -
- -int bm_unload_fast(int handle, int clear_render_targets) {
- - bitmap_entry *be;
- - bitmap *bmp;
- -
- - int n = handle % MAX_BITMAPS;
- -
- - Assert((n >= 0) && (n < MAX_BITMAPS));
- - be = &bm_bitmaps[n];
- - bmp = &be->bm;
- -
- - if (be->type == BM_TYPE_NONE) {
- - return -1; // Already been released
- - }
- -
- - if (be->type == BM_TYPE_USER) {
- - return -1;
- - }
- -
- - if (!clear_render_targets && ((be->type == BM_TYPE_RENDER_TARGET_STATIC) || (be->type == BM_TYPE_RENDER_TARGET_DYNAMIC))) {
- - return -1;
- - }
- -
- - // If it is locked, cannot free it.
- - if (be->ref_count != 0) {
- - nprintf(("BmpMan", "Tried to unload_fast %s that has a lock count of %d.. not unloading\n", be->filename, be->ref_count));
- - return 0;
- - }
- -
- - Assert(be->handle == handle); // INVALID BITMAP HANDLE!
- -
- - // unlike bm_unload(), we handle each frame of an animation separately, for safer use in the graphics API
- - nprintf(("BmpMan", "Fast-unloading %s. %dx%dx%d\n", be->filename, bmp->w, bmp->h, bmp->bpp));
- - bm_free_data_fast(n); // clears flags, bbp, data, etc
- -
- - return 1;
- -}
- -
- -void bm_unlock(int handle) {
- - bitmap_entry *be;
- -
- - if (!bm_inited) bm_init();
- -
- - int bitmapnum = handle % MAX_BITMAPS;
- -
- -#ifndef NDEBUG
- - if (bm_bitmaps[bitmapnum].handle != handle) {
- - mprintf(("bm_unlock - %s: bm_bitmaps[%d].handle = %d, handle = %d\n", bm_bitmaps[bitmapnum].filename, bitmapnum, bm_bitmaps[bitmapnum].handle, handle));
- - }
- -#endif
- -
- - Assert(bm_bitmaps[bitmapnum].handle == handle); // INVALID BITMAP HANDLE
- -
- - Assert((bitmapnum >= 0) && (bitmapnum < MAX_BITMAPS));
- -
- - be = &bm_bitmaps[bitmapnum];
- -
- - be->ref_count--;
- - Assert(be->ref_count >= 0); // Trying to unlock data more times than lock was called!!!
- -}
- -
- -void bm_update_memory_used(int n, int size)
- -{
- - Assert( (n >= 0) && (n < MAX_BITMAPS) );
- - Assert( size >= 0 );
- -
- -#ifdef BMPMAN_NDEBUG
- - Assert( bm_bitmaps[n].data_size == 0 );
- - bm_bitmaps[n].data_size += size;
- - bm_texture_ram += size;
- -#endif
- -}
- -
- -int find_block_of(int n)
- -{
- - int i, cnt = 0, nstart = 0;
- -
- - if (n < 1) {
- - Int3();
- - return -1;
- - }
- -
- - for (i = 0; i < MAX_BITMAPS; i++) {
- - if (bm_bitmaps[i].type == BM_TYPE_NONE) {
- - if (cnt == 0)
- - nstart = i;
- -
- - cnt++;
- - } else {
- - cnt = 0;
- - }
- -
- - if (cnt == n)
- - return nstart;
- + return 1;
- }
- - return -1;
- + return 0;
- }
- diff --git a/code/bmpman/bmpman.h b/code/bmpman/bmpman.h
- index f547d01..edcd40d 100644
- --- a/code/bmpman/bmpman.h
- +++ b/code/bmpman/bmpman.h
- @@ -1,674 +1,275 @@
- +/*
- +* Copyright (C) Volition, Inc. 1999. All rights reserved.
- +*
- +* All source code herein is the property of Volition, Inc. You may not sell
- +* or otherwise commercially exploit the source or things you created based on the
- +* source.
- +*
- +*/
- +
- +
- +
- #ifndef _BMPMAN_H
- #define _BMPMAN_H
- -/*
- - * Copyright (C) Volition, Inc. 1999. All rights reserved.
- - *
- - * All source code herein is the property of Volition, Inc. You may not sell
- - * or otherwise commercially exploit the source or things you created based on the
- - * source.
- - *
- - */
- -
- -/**
- - * @file bmpman.h
- - * Header file for the bitmap manager (bmpman)
- - */
- -
- -/**
- - * @example bm_examples.cpp
- - * @brief This containes examples of bmpman usage
- - */
- -#include "cfile/cfile.h"
- #include "globalincs/pstypes.h"
- +#include "cfile/cfile.h"
- #ifndef NDEBUG
- -#define BMPMAN_NDEBUG //!< Enables BMPMAN debugging code
- +#define BMPMAN_NDEBUG
- #endif
- -/**
- - * @defgroup BMPMAN_CONSTANTS Macro constants used in/with bmpman.h
- - *
- - * @{
- - */
- -
- -/**
- - * @brief How many bitmaps the game can handle
- - *
- - * @attention MAX_BITMAPS shouldn't need to be bumped again. With the fixed bm_release() and it's proper use even the
- - * largest missions should stay under this number. With the largest retail missions and wasteful content we should
- - * still have about 20% of the slots free. If it still goes over then it's something the artists need to fix.
- - * For instance the Terran Mara fighter, with -spec and -glow and using the Shinepack, needs 117 bitmap slots alone.
- - * 111 of those is just for the glowmaps. This number can be greatly reduced if the number of ani frames for another
- - * LOD than LOD0 has fewer or no ani frames. A 37 frame glow ani for LOD2 is little more than a waste of resources.
- - * Future reports of texture corruption should be initially approached with content as the cause and not code.
- - * If anything we could/should reduce MAX_BITMAPS in the future. Where it's at now should accomidate even the
- - * largest mods. -- Taylor
- - */
- -#define MAX_BITMAPS 4750
- -
- -// Flag positions for bitmap.flags
- +#define MAX_BITMAPS 4750 // How many bitmaps the game can handle
- +// NOTE: MAX_BITMAPS shouldn't need to be bumped again. With the fixed bm_release() and it's
- +// proper use even the largest missions should stay under this number. With the largest retail
- +// missions and wasteful content we should still have about 20% of the slots free. If it still
- +// goes over then it's something the artists need to fix. For instance the Terran Mara fighter,
- +// with -spec and -glow and using the Shinepack, needs 117 bitmap slots alone. 111 of those is
- +// just for the glowmaps. This number can be greatly reduced if the number of ani frames for
- +// another LOD than LOD0 has fewer or no ani frames. A 37 frame glow ani for LOD2 is little
- +// more than a waste of resources. Future reports of texture corruption should be initially
- +// approached with content as the cause and not code. If anything we could/should reduce
- +// MAX_BITMAPS in the future. Where it's at now should accomidate even the largest mods.
- +// -- Taylor
- +
- +
- +#define BMP_AABITMAP (1<<0) // antialiased bitmap
- +#define BMP_TEX_XPARENT (1<<1) // transparent texture
- +#define BMP_TEX_OTHER (1<<2) // so we can identify all "normal" textures
- +#define BMP_TEX_DXT1 (1<<3) // dxt1 compressed 8r8g8b1a (24bit)
- +#define BMP_TEX_DXT3 (1<<4) // dxt3 compressed 8r8g8b4a (32bit)
- +#define BMP_TEX_DXT5 (1<<5) // dxt5 compressed 8r8g8b8a (32bit)
- +#define BMP_TEX_CUBEMAP (1<<6) // a texture made for cubic environment map
- // ***** NOTE: bitmap.flags is an 8-bit value, no more BMP_TEX_* flags can be added unless the type is changed!! ******
- -#define BMP_AABITMAP (1<<0) //!< antialiased bitmap
- -#define BMP_TEX_XPARENT (1<<1) //!< transparent texture
- -#define BMP_TEX_OTHER (1<<2) //!< so we can identify all "normal" textures
- -#define BMP_TEX_DXT1 (1<<3) //!< dxt1 compressed 8r8g8b1a (24bit)
- -#define BMP_TEX_DXT3 (1<<4) //!< dxt3 compressed 8r8g8b4a (32bit)
- -#define BMP_TEX_DXT5 (1<<5) //!< dxt5 compressed 8r8g8b8a (32bit)
- -#define BMP_TEX_CUBEMAP (1<<6) //!< a texture made for cubic environment map
- -
- -// Combined flags
- -#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 ) //!< Compressed textures
- -#define BMP_TEX_NONCOMP ( BMP_TEX_XPARENT | BMP_TEX_OTHER ) //!< Non-compressed textures
- -#define BMP_TEX_ANY ( BMP_TEX_COMP | BMP_TEX_NONCOMP ) //!< Any texture
- -
- -// Flag positions for bitmap.type
- -#define BMP_FLAG_RENDER_TARGET_STATIC (1<<0) //!< Texture is a static type
- -#define BMP_FLAG_RENDER_TARGET_DYNAMIC (1<<1) //!< Texture is a dynamic type (animation)
- -#define BMP_FLAG_CUBEMAP (1<<2) //!< Texture is a cubemap
- -
- -// Bitmap types
- -enum BM_TYPE
- -{
- - BM_TYPE_NONE = 0, //!< No type
- - BM_TYPE_USER, //!< in-memory
- - BM_TYPE_PCX, //!< PCX
- - BM_TYPE_TGA, //!< 16 or 32 bit targa
- - BM_TYPE_DDS, //!< generic identifier for DDS
- - BM_TYPE_PNG, //!< PNG
- - BM_TYPE_JPG, //!< 32 bit jpeg
- - BM_TYPE_ANI, //!< in-house ANI format
- - BM_TYPE_EFF, //!< specifies any type of animated image, the EFF itself is just text
- -
- - // special types
- - BM_TYPE_RENDER_TARGET_STATIC, //!< 24/32 bit setup internally as a static render target
- - BM_TYPE_RENDER_TARGET_DYNAMIC, //!< 24/32 bit setup internally as a dynamic render target
- -
- - // Compressed types (bitmap.c_type)
- - BM_TYPE_DXT1, //!< 24 bit with switchable alpha
- - BM_TYPE_DXT3, //!< 32 bit with 4 bit alpha
- - BM_TYPE_DXT5, //!< 32 bit with 8 bit alpha
- - BM_TYPE_CUBEMAP_DDS, //!< generic DDS cubemap (uncompressed cubemap surface)
- - BM_TYPE_CUBEMAP_DXT1, //!< 24-bit cubemap (compressed cubemap surface)
- - BM_TYPE_CUBEMAP_DXT3, //!< 32-bit cubemap (compressed cubemap surface)
- - BM_TYPE_CUBEMAP_DXT5 //!< 32-bit cubemap (compressed cubemap surface)
- -};
- -
- -/**
- - * @}
- - */
- -
- -struct bitmap
- -{
- - short w; //!< Width, in number of pixels
- - short h; //!< Height, in number of pixels
- - short rowsize; //!< What you need to add to go to next row
- - ubyte bpp; //!< Requested bitdepth of each pixel. ( 7, 8, 15, 16, 24, 32)
- - ubyte true_bpp; //!< The image's actual bitdepth
- - ubyte flags; //!< Various texture type flags. @see BMPMAN_CONSTANTS
- - ptr_u data; //!< Pointer to data, or maybe offset into VRAM.
- - ubyte *palette; /**< @brief Pointer to this bitmap's palette (if it has one).
- - * @details If BMP_NO_PALETTE_MAP flag is cleared, this palette just points to the screen palette. (gr_palette)
- - */
- -};
- -
- -extern int bm_texture_ram; //!< how many bytes of textures are used.
- -
- -extern int Bm_paging; //!< Bool type that indicates if BMPMAN is currently paging.
- -
- -extern const BM_TYPE bm_type_list[]; //!< List of valid bitmap types
- -extern const char *bm_ext_list[]; //!< List of extensions for those types
- -extern const int BM_NUM_TYPES; //!< Calculated number of bitmap types
- -extern const BM_TYPE bm_ani_type_list[]; //!< List of valid bitmap animation types
- -extern const char *bm_ani_ext_list[]; //!< List of extensions for those types
- -extern const int BM_ANI_NUM_TYPES; //!< Calculated number of bitmap animation types
- -
- -extern int GLOWMAP; //!< References a map that is a fully lit version of its index -Bobboau
- -extern int SPECMAP; //!< References a map that is for specular mapping -Bobboau
- -extern int ENVMAP; //!< References a map that is for environment mapping -Bobboau
- -extern int NORMMAP; //!< Normal mapping
- -extern int HEIGHTMAP; //!< Height map for normal mapping
- -extern int MISCMAP; //!< Utility map, to be utilized for various things shader authors can come up with
- -
- -/**
- - * @brief Initilizes the bitmap manager
- - */
- +
- +//compressed texture types
- +#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 )
- +
- +//non compressed textures
- +#define BMP_TEX_NONCOMP ( BMP_TEX_XPARENT | BMP_TEX_OTHER )
- +
- +// any texture type
- +#define BMP_TEX_ANY ( BMP_TEX_COMP | BMP_TEX_NONCOMP )
- +
- +#define BMP_FLAG_RENDER_TARGET_STATIC (1<<0)
- +#define BMP_FLAG_RENDER_TARGET_DYNAMIC (1<<1)
- +#define BMP_FLAG_CUBEMAP (1<<2)
- +
- +typedef struct bitmap {
- + int id; // defines a bitmap ID
- + short w, h; // Width and height
- + short rowsize; // What you need to add to go to next row
- + ubyte bpp; // How many bits per pixel it is. (7,8,15,16,24,32) (what is requested)
- + ubyte true_bpp; // How many bits per pixel the image actually is.
- + ubyte flags; // See the BMP_???? defines for values (this isn't for the BMP_FLAG_* stuff)
- + ptr_u data; // Pointer to data, or maybe offset into VRAM.
- + ubyte *palette; // If bpp==8, this is pointer to palette. If the BMP_NO_PALETTE_MAP flag
- + // is not set, this palette just points to the screen palette. (gr_palette)
- +} bitmap;
- +
- +
- +extern int Bm_paging;
- +
- void bm_init();
- -/**
- - * @brief Closes the bitmap manager, freeing any allocated memory used by bitmaps. Is called at program close.
- - */
- void bm_close();
- -/**
- - * Gets the cache slot of the bitmap indexed by handle.
- - *
- - * @details if the bitmap is an ani, gets the first frame
- - *
- - * @returns The cache slot index of the bitmap if handle is valid
- - *
- - * @note If the handle is invalid, an Assert() fails
- - */
- int bm_get_cache_slot(int bitmap_id, int separate_ani_frames);
- -/**
- - * @brief Gets the next available bitmap slot.
- - */
- int bm_get_next_handle();
- -/**
- - * @brief Allocates memory for the given handle.
- - *
- - * @returns A pointer to the allocated vm if successful,
- - * @returns Null, if unsuccessful
- - *
- - * @note z64 - This function looks fishy. Not only is handle not used in release builds, but bm_bitmaps[handle].size
- - * and bm_texture_size aren't modified unless this is a debug build
- - */
- -void *bm_malloc(int handle, int size);
- -
- -/**
- - * @brief (DEBUG) Similar to bm_malloc, but only updates how much memory is used
- - *
- - * @note z64 - Also fishy (see bm_malloc)
- - */
- void bm_update_memory_used(int n, int size);
- -class bitmap_lookup {
- - float *Bitmap_data;
- -
- - int Width;
- - int Height;
- - int Num_channels;
- -
- - float map_texture_address(float address);
- -public:
- - bitmap_lookup(int bitmap_num);
- - ~bitmap_lookup();
- -
- - bool valid();
- -
- - float get_channel_red(float u, float v);
- - float get_channel_green(float u, float v);
- - float get_channel_blue(float u, float v);
- - float get_channel_alpha(float u, float v);
- -};
- -
- -/**
- - * @brief Loads a bitmap so we can draw with it later.
- - *
- - * @param filename
- - *
- - * @returns The bitmap number if successful, else
- - * @returns a negative value if not
- - */
- -int bm_load(const char* filename);
- +// how many bytes of textures are used.
- +extern int bm_texture_ram;
- -/**
- - * @brief Loads a bitmap so we can draw with it later. (Preferred version)
- - *
- - * @param filename
- - *
- - * @returns The bitmap number if successful, else
- - * @returns a negative value if not
- - */
- +// This loads a bitmap so we can draw with it later.
- +// It returns a negative number if it couldn't load
- +// the bitmap. On success, it returns the bitmap
- +// number.
- +int bm_load(const char* filename);
- int bm_load(const SCP_string& filename);
- -/**
- - * @brief Reloads a bitmap as a duplicate.
- - *
- - * @details This function basically allows you to load a bitmap which already exists (by filename). This is useful
- - * because in some cases we need to have a bitmap which is locked in screen format _and_ texture format, such as
- - * the pilot pics and squad logos
- - *
- - * @param filename
- - *
- - * @returns The bitmap number if successful, else
- - * @returns a negative value if not
- - */
- +// special load function. basically allows you to load a bitmap which already exists (by filename).
- +// this is useful because in some cases we need to have a bitmap which is locked in screen format
- +// _and_ texture format, such as pilot pics and squad logos
- int bm_load_duplicate(const char *filename);
- -/**
- - * Loads a bitmap which exists somewhere in the RAM.
- - *
- - * @param bpp The bitdepth of the bitmap
- - * @param w The width of the bitmap
- - * @param h The height of the bitmap
- - * @param[in] data The bitmap's data glob
- - * @param flags
- - *
- - * @note The used RAM cannot be freed until bm_release is called on the created bitmap
- - */
- +// Creates a bitmap that exists in RAM somewhere, instead
- +// of coming from a disk file. You pass in a pointer to a
- +// block of data. The data can be in the following formats:
- +// 8 bpp (mapped into game palette)
- +// 32 bpp
- +// On success, it returns the bitmap number. You cannot
- +// free that RAM until bm_release is called on that bitmap.
- +// See example at bottom of this file
- int bm_create(int bpp, int w, int h, void *data = NULL, int flags = 0);
- -/**
- - * @brief Unloads a bitmap's data, but not the bitmap info
- - *
- - * @details The bm number (n) may be reused once this function has been called on it. However, it will have to be paged
- - * in the next time it is locked.
- -
- - * @param handle The index number of the bitmap to free
- - * @param clear_render_targets If true, release a render target
- - * @param nodebug If true, exclude certain debug messages
- - *
- - * @returns 0 if not successful,
- - * @returns 1 if successful
- - */
- -int bm_unload(int handle, int clear_render_targets = 0, bool nodebug = false);
- -
- -/**
- - * @brief Quickly unloads a bitmap's data, ignoring the load_count
- - *
- - * @details Similar to bm_unload(), except that it can be safely used to free data without worrying about load_count.
- - * It's safe to use in relation to bm_release() and in gr_*_texture functions
- - *
- - * @param handle The bm number of the bitmap to free
- - * @param clear_render_targets If true, release a render target
- - *
- - * @note bm_free_data_fast() is used here and NOT bm_free_data()
- - */
- -int bm_unload_fast(int handle, int clear_render_targets = 0);
- -
- -/**
- - * @brief Frees both a bitmap's data and it's associated slot.
- - *
- - * @details Once called, the bm number 'n' cannot be used until bm_load or bm_create is re-inits the slot.
- - *
- - * @param handle The index number of the bitmap to release
- - * @param clear_render_targets If nonzero, also release render targets
- - *
- - * @returns 1 on success,
- - * @returns 0 otherwise
- - *
- - * @note If the passed handle is that of an ANI, it frees EVERY frame. Be sure to only pass the handle of the first frame!
- - *
- - * @todo upgrade return type and clear_render_targets type to bools
- - */
- -int bm_release(int handle, int clear_render_targets = 0);
- -
- -/**
- - * @brief Loads a bitmap sequance so we can draw with it.
- - *
- - * @param[in] filename
- - * @param[out] nframes If non-null, set to the number of frames the animation has
- - * @param[out] fps If non-null, set to the fps of this animation
- - * @param[out] keyframe if non null, set to the keyframe index of this animation
- - * @param[in] can_drop_frames If set, allows dropped frames
- - * @param[in] dir_type Directory type
- - *
- - * @returns The bm number of the first bitmap in the sequence if successful, or
- - * @returns A negative value if unsuccessful
- - */
- -int bm_load_animation(const char *filename, int *nframes = NULL, int *fps = NULL, int *keyframe = NULL, int can_drop_frames = 0, int dir_type = CF_TYPE_ANY);
- -
- -/**
- - * @brief Loads either animation (bm_load_animation) or still image (bm_load)
- - *
- - * @param[in] filename
- - * @param[out] nframes If non-null and loading was successful, set to the number of frames the animation has
- - * @param[out] fps If non-null and loading was successful, set to the fps of this animation
- - * @param[out] keyframe if non null and loading was successful, set to the keyframe index of this animation
- - * @param[in] can_drop_frames
- - * @param[in] dir_type
- - *
- - * @returns The bm number of the first bitmap in the sequence if successful, or
- - * @returns A negative value if unsuccessful
- - */
- -int bm_load_either(const char *filename, int *nframes = NULL, int *fps = NULL, int *keyframe = NULL, int can_drop_frames = 0, int dir_type = CF_TYPE_ANY);
- -
- -/**
- - * @brief Locks down the bitmap indexed by bitmapnum.
- - *
- - * @details Also converts the bitmap to the appropriate format specified by bpp and flags. Only lock a bitmap when you
- - * need it!
- - *
- - * @param handle The number indexing the desired bitmap
- - * @param bpp The desired bpp of the bitmep
- - * @param flags The desired bitmap format
- - * @param nodebug
- -
- - * @returns A pointer to the bitmap that's valid until bm_unlock is called if successful, or
- - * @returns NULL if unsuccessful
- - */
- -bitmap* bm_lock(int handle, ubyte bpp, ubyte flags, bool nodebug = false);
- -
- -/**
- - * @brief Returns a unique signiature for the bitmap indexed by handle
- - *
- - * @details A signature will change when the bitmap's data changes
- - */
- -uint bm_get_signature(int handle);
- -
- -/**
- - * @brief Returns the image type of the given bitmap handle
- - */
- -BM_TYPE bm_get_type(int handle);
- -
- -/**
- - * @brief Unlocks a bitmap
- - *
- - * @details Decrements the ref_count member of the bitmap_entry struct, A bitmap can only be unloaded when the
- - * ref_count is 0
- - */
- -void bm_unlock(int handle);
- -
- -/**
- - * @brief Checks if the bitmap indexed by handle is valid
- - *
- - * @details Some early known false or out of range handles (such as negative) are checked within
- - * an initial routine pass, followed by a more thorough check routine to ensure the
- - * series of bitmaps within the bm_bitmaps[] structure have not become invalid.
- - *
- - * @returns Nonzero if valid, else
- - * @returns Zero otherwise
- - *
- - * @todo z64 - Returned value is essentially a bool type, need to check all caller functions to see if it can safely
- - * be updated to reflect this
- - */
- -int bm_is_valid(int handle);
- -
- -/**
- - * @brief Gets info on the bitmap indexed by handle.
- - *
- - * @param[out] w If non-null, gets the width
- - * @param[out] h If non-null, gets the heigth
- - * @param[out] flags If non-null, gets the flags
- - * @param[out] nframs If non-null, gets the nframes
- - * @param[out] fps If non-null, gets the fps
- - *
- - * @returns The handle on success, or
- - * @returns The handle to the first frame on success, or
- - * @returns -1 on failure
- - */
- -int bm_get_info(int handle, int *w = NULL, int * h = NULL, ubyte * flags = NULL, int *nframes = NULL, int *fps = NULL);
- -
- -/**
- - * @brief Gets the filename of the bitmap indexed by handle
- - *
- - * @param[out] filename The filename of the bitmap, if successful. Is set to an empty string if unseccessful
- - *
- - * @todo z64 - maybe deprecate this in favor of an SCP_string version
- - */
- -void bm_get_filename(int bitmapnum, char *filename);
- -
- -/**
- - * @brief Gets the filename of the bitmap indexed by handle, which must exist.
- - *
- - * @details If the bitmap does not exist (i.e. the handle is invalid), then an Assertion halts program execution.
- - *
- - * @returns A const char* to the filename of the bitmap
- - *
- - * @todo z64 - maybe deprecate this in favor of an SCP_string version.
- - * @todo z64 - maybe combine this with the other bm_get_filename function like so:
- - * void bm_get_filename(int handle, SCP_string *filename, bool must_exist = false);
- - */
- -const char *bm_get_filename(int handle);
- +// Frees up a bitmap's data, but bitmap number 'n' can
- +// still be used, it will just have to be paged in next
- +// time it is locked.
- +int bm_unload(int n, int clear_render_targets = 0, bool nodebug = false);
- +
- +// like bm_unload() except that it's safe to use to free data without worrying about
- +// load_count so it's safe to use in relation to bm_release() and in gr_*_texture functions
- +int bm_unload_fast(int n, int clear_render_targets = 0);
- +
- +// Frees up a bitmap's data, and it's slot, so bitmap
- +// number 'n' cannot be used anymore, and bm_load or
- +// bm_create might reuse the slot.
- +int bm_release(int n, int clear_render_targets = 0);
- +
- +// This loads a bitmap sequence so we can draw with it later.
- +// It returns a negative number if it couldn't load
- +// the bitmap. On success, it returns the bitmap
- +// number of the first frame and nframes is set.
- +extern int bm_load_animation(const char *filename, int *nframes = NULL, int *fps = NULL, int *keyframe = NULL, int can_drop_frames = 0, int dir_type = CF_TYPE_ANY);
- -/**
- - * @brief Loads all data for all bitmaps that have been requested to be loaded
- - *
- - * @note This function is not defined.
- - */
- -void bm_gfx_load_all();
- -
- -/**
- - * @brief Unloads all used bitmaps, should only ever be called by game_shutdown()
- - *
- - * @todo Maybe move this declaration into bmpman.cpp and then extern this function within game_shutdown() to
- - * ensure it only ever gets called there.
- - */
- -void bm_unload_all();
- -
- -/**
- - * @brief Gets the palette for a given bitmap indexed by handle, and optionally the filename
- - *
- - * @param[out] pal Is set to reference the bitmap's palette
- - * @param[out] name (optional) Is set to the bitmap's filename
- - *
- - * @todo Maybe get rid of the optional filename and have the callers call bm_get_filename. Less efficient, however.
- - */
- -void bm_get_palette(int handle, ubyte *pal, char *name);
- -
- -/**
- - * @brief Hack to get a pixel from a bitmap
- - *
- - * @details only works good in 8bpp mode
- - *
- - * @note This function is not defined.
- - */
- -void bm_gfx_get_pixel(int bitmap, float u, float v, ubyte *r, ubyte *g, ubyte *b);
- -
- -/**
- - * @brief (DEBUG) Gets memory size, in bytes, of the locked bitmaps
- - *
- - * @details Both params are non-optional, and must be non-null. There's currently no safety checks on either.
- - *
- - * @param ntotal[out] Memory size, in bytes, of the locked bitmaps
- - * @param nnew[out] Memory size, in bytes, of the bitmaps that were locked since the last frame
- - *
- - * @note This is a debug function, and is undefined within release builds
- - */
- +//Loads either animation (bm_load_animation) or still image (bm_load)
- +extern int bm_load_either(const char *filename, int *nframes = NULL, int *fps = NULL, int *keyframe = NULL, int can_drop_frames = 0, int dir_type = CF_TYPE_ANY);
- +
- +// This locks down a bitmap and returns a pointer to a bitmap
- +// that can be accessed until you call bm_unlock. Only lock
- +// a bitmap when you need it! This will convert it into the
- +// appropriate format also.
- +extern bitmap * bm_lock(int bitmapnum, ubyte bpp, ubyte flags, bool nodebug = false);
- +
- +//gets the image type
- +ubyte bm_get_type(int handle);
- +
- +// Unlocks a bitmap
- +extern void bm_unlock(int bitmapnum);
- +
- +//WMC - Returns 0 if invalid, nonzero if valid
- +extern int bm_is_valid(int handle);
- +
- +// Gets info. w,h,or flags,nframes or fps can be NULL if you don't care.
- +//WMC - Returns -1 on failure, handle or first frame handle on success.
- +int bm_get_info(int bitmapnum, int *w = NULL, int * h = NULL, ubyte * flags = NULL, int *nframes = NULL, int *fps = NULL);
- +
- +// get filename
- +extern void bm_get_filename(int bitmapnum, char *filename);
- +
- +// call to load all data for all bitmaps that have been requested to be loaded
- +extern void bm_gfx_load_all();
- +extern void bm_unload_all();
- +
- +// Returns number of bytes of bitmaps locked this frame
- +// ntotal = number of bytes of bitmaps locked this frame
- +// nnew = number of bytes of bitmaps locked this frame that weren't locked last frame
- void bm_get_frame_usage(int *ntotal, int *nnew);
- -/**
- - * @brief Reloads an existing bmpman slot with different bitmap
- - *
- - * @param[in] filename The filename of the image to load
- - *
- - * @returns The bitmap handle on success, or
- - * @returns A negative value on failure
- - *
- - * @note This should only be used if you are certain the new picture is the same type, has same dimensions, etc.
- - */
- +// Reload a different image into an existing bmpman slot
- int bm_reload(int bitmap_handle, const char* filename);
- -/**
- - * @brief Tells bmpman to start keeping track of what bitmaps are used where
- - */
- -void bm_page_in_start();
- +/*
- +* Example on using bm_create
- +*
- +{
- +static int test_inited = 0;
- +static int test_bmp;
- +static uint test_bmp_data[128*64];
- +
- +if ( !test_inited ) {
- +test_inited = 1;
- +// Create the new bitmap and fill in its data.
- +// When you're done with it completely, call
- +// bm_release to free up the bitmap handle
- +test_bmp = bm_create( 32, 128, 64, test_bmp_data );
- +int i,j;
- +for (i=0; i<64; i++ ) {
- +for (j=0; j<64; j++ ) {
- +uint r=i*4;
- +test_bmp_data[j+i*128] = r;
- +}
- +}
- +}
- +
- +bm_unload(test_bmp); // this pages out the data, so that the
- +// next bm_lock will convert the new data to the
- +// correct bpp
- +
- +// put in new data
- +int x,y;
- +gr_reset_clip();
- +for (y=0; y<64; y++)
- +for (x=0; x<128; x++ )
- +test_bmp_data[y*128+x] = 15;
- +
- +// Draw the bitmap to upper left corner
- +gr_set_bitmap(test_bmp);
- +gr_bitmap( 0,0 );
- +}
- +*/
- +
- +
- +//============================================================================
- +// Paging stuff
- +//============================================================================
- -/**
- - * @brief Tells bmpman to stop paging (?)
- - */
- +void bm_page_in_start();
- void bm_page_in_stop();
- // Paging code in a library should call these functions
- // in its page in function.
- -/**
- - * @brief Marks a texture as being used for this level
- - *
- - * @param[in] num_frames If specified, assumes this is an animated texture
- - */
- +// Marks a texture as being used for this level
- +// If num_frames is passed, assume this is an animation
- void bm_page_in_texture(int bitmapnum, int num_frames = 0);
- -/**
- - * @brief Marks a textures as being used for level and is transparant
- - *
- - * @param[in] num_frames If specified, assumes this is an animated texture
- - */
- +// marks a texture as being a transparent textyre used for this level
- +// Marks a texture as being used for this level
- +// If num_frames is passed, assume this is an animation
- void bm_page_in_xparent_texture(int bitmapnum, int num_frames = 1);
- -/**
- - * @brief Marks a texture as being used for this level, and is anti-aliased
- - *
- - * @param[in] num_frames If specified, assumes this is an animated texture
- - */
- +// Marks an aabitmap as being used for this level
- +// If num_frames is passed, assume this is an animation
- void bm_page_in_aabitmap(int bitmapnum, int num_frames = 1);
- -/**
- - * @brief Unloads the bitmap indexed by handle that was previously paged-in
- - *
- - * @returns 0 If the bitmap had already been released, or
- - * @returns 0 If the handle is invalid, or
- - * @returns 1 If successful
- - */
- -bool bm_page_out(int handle);
- -
- -/**
- - * @brief Sets BMPMAN's memory mode
- - *
- - * @details 0 = High memory;
- - * 1 = Low memory (loads every other frame of ani's);
- - * 2 = Debug low memory (only use first frame of each ani)
- - *
- - * @todo This should use an enum, or instead allow an arbitrary number to drop frames (like 1/2, 1/3, etc.)
- - */
- +// unload a texture that was paged in
- +int bm_page_out(int handle);
- +
- +//
- +// Mode: 0 = High memory
- +// 1 = Low memory ( every other frame of ani's)
- +// 2 = Debug low memory ( only use first frame of each ani )
- void bm_set_low_mem(int mode);
- -/**
- - * @brief Sets bm_set_components and bm_get_components to reference screen format functions
- - */
- -void BM_SELECT_SCREEN_FORMAT();
- +const char *bm_get_filename(int handle);
- -/**
- - * @brief Sets bm_set_components and bm_get_components to reference texture format functions
- - */
- +void BM_SELECT_SCREEN_FORMAT();
- void BM_SELECT_TEX_FORMAT();
- -
- -/**
- - * @brief Sets bm_set_components and bm_get_components to reference texture format functions (with alpha)
- - */
- void BM_SELECT_ALPHA_TEX_FORMAT();
- -/**
- - * @brief Functional pointer that references any of the bm_set_components functions.
- - *
- - * @details The bm_set_components functions packs the RGBA values into the ubyte array referenced by pixel, whose
- - * format differs according to its bpp value and presence of an alpha channel. The RGBA values are scaled accordingly.
- - *
- - * @param[out] pixel The pixel to set
- - * @param[in] r Red value (may not be NULL)
- - * @param[in] g Green value (may not be NULL)
- - * @param[in] b Blue value (may not be NULL)
- - * @param[in] a Alpha value (currently ignored)
- - *
- - * @note z64 - These functions were made predating the introduction of C++ classes, and are basically the equivalent
- - * of Pixel::set(ubyte *r, ubyte *b, ubyte *g). The original comment mentions that any of the rgba params may be
- - * NULL, but this is by far _NOT_ the case, as a NULL value will cause undefined behavior (really really bad chroma
- - * corruption)
- - *
- - * @note These functions assume the incoming bitdepth will always be >= to the outgoing bitdepth of the pixel. Should
- - * the incoming bitdepth be lower, the outgoing values will appear darker than they should be
- - */
- +// set the rgba components of a pixel, any of the parameters can be NULL
- extern void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- -
- -/**
- - * @brief Functional pointer that references any of the bm_set_components_32 functions.
- - *
- - * @details The bm_set_components functions packs the RGBA values into the ubyte array referenced by pixel, whose
- - * format differs according to its bpp value and presence of an alpha channel. The RGBA values are scaled accordingly.
- - *
- - * @see bm_set_components
- - */
- extern void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- +void bm_set_components_argb_d3d_16_screen(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- +void bm_set_components_argb_d3d_32_screen(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- +void bm_set_components_argb_d3d_16_tex(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- +void bm_set_components_argb_d3d_32_tex(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- -/**
- - * @brief Sets the 16bpp screen pixel to the specified RGBA value
- - *
- - * @see bm_set_components
- - */
- -void bm_set_components_argb_16_screen(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- -
- -/**
- - * @brief Sets the 32bpp screen pixel to the specified RGBA value
- - *
- - * @see bm_set_components
- - */
- -void bm_set_components_argb_32_screen(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- -
- -/**
- - * @brief Sets the 16bpp texture pixel to the specified RGBA value
- - *
- - * @see bm_set_components
- - */
- -void bm_set_components_argb_16_tex(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- -
- -/**
- - * @brief Sets the 32bpp texture pixel to the specified RGBA value
- - *
- - * @see bm_set_components
- - */
- -void bm_set_components_argb_32_tex(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- -
- -/**
- - * @brief Gets the RGBA components of a pixel according to the selected mode
- - *
- - * @see BM_SELECT_SCREEN_FORMAT() BM_SELECT_TEX_FORMAT() BM_SELECT_ALPHA_TEX_FORMAT()
- - */
- +// get the rgba components of a pixel, any of the parameters can be NULL
- void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
- -/**
- - * @brief Returns the compression type of the bitmap indexed by handle
- - */
- -int bm_is_compressed(int handle);
- -
- -/**
- - * @brief Gets the correct TCACHE_TYPE for compressed graphics (uncompressed are assumed TCACHE_TYPE_NORMAL)
- - */
- -int bm_get_tcache_type(int handle);
- -
- -/**
- - * @brief Gets the size, in bytes, taken up by the bitmap indexed by handle
- - */
- -size_t bm_get_size(int handle);
- -
- -/**
- - * @brief Gets the number of mipmaps of the indexed texture
- - */
- -int bm_get_num_mipmaps(int handle);
- -
- -/**
- - * @brief Checks to see if the indexed bitmap has an alpha channel
- - *
- - * @note Currently just checks if the bitmap is 32bpp and is not a .PCX
- - */
- -bool bm_has_alpha_channel(int handle);
- -
- -/**
- - * @brief (DEBUG) Prints all loaded bitmaps to an outwindow
- - */
- +extern int GLOWMAP; //this holds a reference to a map that is a fully lit version of its index -Bobboau
- +extern int SPECMAP; //this holds a reference to a map that is for specular mapping -Bobboau
- +extern int ENVMAP; //this holds a reference to a map that is for environment mapping -Bobboau
- +extern int NORMMAP; // normal mapping
- +extern int HEIGHTMAP; // height map for normal mapping
- +extern int MISCMAP; // Utility map, to be utilized for various things shader authors can come up with
- +
- +int bm_is_compressed(int num);
- +int bm_get_tcache_type(int num);
- +int bm_get_size(int num);
- +int bm_get_num_mipmaps(int num);
- +int bm_has_alpha_channel(int handle);
- +
- void bm_print_bitmaps();
- -/**
- - * @brief Creates a render target as close to the desired resolution as possible.
- - *
- - * @returns the handle of an avilable render target if successful, or
- - * @returns -1 if not successful
- - *
- - * @note BM_FLAG_RENDER_TARGET_STATIC are drawn once/infrequently, while BM_FLAG_RENDER_TARGET_DYNAMIC are drawn roughly once every frame
- - */
- int bm_make_render_target(int width, int height, int flags);
- +int bm_is_render_target(int bitmap_id);
- +int bm_set_render_target(int handle, int face = -1);
- -/**
- - * @brief Checks to see if the given bitmap indexed by handle is a render target
- - *
- - * @returns The render type (BM_TYPE) if it is a render target, or
- - * @returns 0 if it is not
- - */
- -int bm_is_render_target(int handle);
- -
- -/**
- - * @brief (GR function) Calls gr_bm_set_render target for the given bitmap indexed by handle
- - *
- - * @returns true if successful, or
- - * @returns false if unsuccessful
- - */
- -bool bm_set_render_target(int handle, int face = -1);
- -
- -/**
- - * @brief Loads and parses an .EFF
- - *
- - * @param[in] filename The filename of the .EFF
- - * @param[in] dir_type
- - * @param[out] nframes (optional) If given, is set to the number of frames this .EFF has
- - * @param[out] nfps (optional) If given, is set to the fps of this .EFF
- - * @param[out] key (optional) If given, is set to the keyframe index of this .EFF
- - * @param[out] type (optional) If given, is set to the BM_TYPE of the .EFF
- - *
- - * @returns true If successful
- - * @returns false If not successful
- - */
- -bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type);
- -
- -#endif
- +int bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, ubyte *type);
- +#endif
- \ No newline at end of file
- --
- 1.9.5.msysgit.0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement