Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions code/bmpman/bm_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ union bm_extra_info {
// stuff for static animations
BM_TYPE type; //!< type for individual images
char filename[MAX_FILENAME_LEN]; //!< filename for individual images
bool in_subdir; //!< Whether frames are in their own subdirectory
} eff;
struct {
bool is_apng; //!< Is this animation an APNG?
Expand Down
43 changes: 40 additions & 3 deletions code/bmpman/bmpman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "pngutils/pngutils.h"
#include "ship/ship.h"
#include "tgautils/tgautils.h"
#include "cfile/cfilesystem.h"

#include <ctype.h>
#include <limits.h>
Expand All @@ -47,7 +48,20 @@
/**
* @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 ); }
#define EFF_FILENAME_CHECK \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This macro is getting a bit too big, how about converting it to a static function?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC I didn't because it was the more complicated route and I didn't want to bundle potentially error-prone refactoring like that with the feature. It could certainly be done separately.

{ \
if ( be->type == BM_TYPE_EFF ) { \
strcpy_s( filename, be->info.ani.eff.filename ); \
if (be->info.ani.eff.in_subdir) { \
if (!cf_set_temp_subdir_pathtype(bm_bitmaps[be->info.ani.first_frame].filename)) { \
mprintf(("BMPMAN: Failed to set temporary pathtype for %s: EFF_FILENAME_CHECK failed!\n", be->filename)); \
} \
} \
} \
else { \
strcpy_s( filename, be->filename ); \
} \
}
// --------------------------------------------------------------------------------------------------------------------
// Monitor variables
MONITOR(NumBitmapPage)
Expand Down Expand Up @@ -83,6 +97,8 @@ const int BM_ANI_NUM_TYPES = sizeof(bm_ani_type_list) / sizeof(bm_ani_type_list[
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;

extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];

// --------------------------------------------------------------------------------------------------------------------
// Declaration of protected variables (defined in cmdline.cpp).
extern int Cmdline_cache_bitmaps;
Expand Down Expand Up @@ -1311,8 +1327,9 @@ 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) {
bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type, bool *in_subdir) {
int frames = 0, fps = 30, keyframe = 0;
bool subdir = false;
char ext[8];
BM_TYPE c_type = BM_TYPE_NONE;
char file_text[1024];
Expand Down Expand Up @@ -1350,6 +1367,10 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
return false;
}

if (optional_string( "$Subdir:" )) {
stuff_boolean(&subdir);
}

// done with EFF so unpause parsing so whatever can continue
unpause_parse();

Expand Down Expand Up @@ -1386,6 +1407,8 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
if (key)
*key = keyframe;

*in_subdir = subdir;

return true;
}

Expand Down Expand Up @@ -1501,6 +1524,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
char filename[MAX_FILENAME_LEN];
int reduced = 0;
int anim_fps = 0, anim_frames = 0, key = 0;
bool in_subdir = false;
float anim_total_time = 0.0f;
int anim_width = 0, anim_height = 0;
BM_TYPE type = BM_TYPE_NONE, eff_type = BM_TYPE_NONE, c_type = BM_TYPE_NONE;
Expand Down Expand Up @@ -1597,7 +1621,7 @@ 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, &in_subdir)) {
mprintf(("BMPMAN: Error reading EFF\n"));
if (img_cfp != nullptr)
cfclose(img_cfp);
Expand Down Expand Up @@ -1695,6 +1719,10 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
return -1;
}

if (in_subdir) {
cf_set_temp_subdir_pathtype(filename);
}

int first_handle = bm_get_next_handle();

for (i = 0; i < anim_frames; i++) {
Expand Down Expand Up @@ -1760,6 +1788,11 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
bm_bitmaps[n + i].num_mipmaps = mm_lvl;
bm_bitmaps[n + i].mem_taken = (size_t)img_size;
bm_bitmaps[n + i].dir_type = dir_type;
bm_bitmaps[n + i].info.ani.eff.in_subdir = in_subdir;
if (in_subdir)
bm_bitmaps[n + i].dir_type = CF_TYPE_TEMP_SUBDIR_LOOKUP;
else
bm_bitmaps[n + i].dir_type = dir_type;

bm_bitmaps[n + i].load_count++;

Expand Down Expand Up @@ -2594,6 +2627,10 @@ void bm_page_in_stop() {
if ((bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].type != BM_TYPE_RENDER_TARGET_DYNAMIC) && (bm_bitmaps[i].type != BM_TYPE_RENDER_TARGET_STATIC)) {
if (bm_bitmaps[i].preloaded) {
if (bm_preloading) {
if (bm_bitmaps[i].type == BM_TYPE_EFF && bm_bitmaps[i].info.ani.eff.in_subdir) {
cf_set_temp_subdir_pathtype(bm_bitmaps[i].filename);
}

if (!gr_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded == 2))) {
mprintf(("Out of VRAM. Done preloading.\n"));
bm_preloading = 0;
Expand Down
11 changes: 6 additions & 5 deletions code/bmpman/bmpman.h
Original file line number Diff line number Diff line change
Expand Up @@ -676,15 +676,16 @@ bool bm_set_render_target(int handle, int face = -1);
*
* @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
* @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
* @param[out] in_subdir (optional) If given, is set to true if the frames of this .EFF are in a subdir
*
* @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);
bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type, bool *in_subdir);

/**
* @brief Calculates & returns the current frame of an animation
Expand Down
43 changes: 43 additions & 0 deletions code/cfile/cfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA },
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
{ CF_TYPE_TEMP_SUBDIR_LOOKUP, NULL, ".pcx .tga .jpg .png .dds", CF_TYPE_DATA },
};


Expand Down Expand Up @@ -135,6 +136,8 @@ void cfile_close()

cf_free_secondary_filelist();

vm_free(Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path);

cfile_inited = 0;
}

Expand Down Expand Up @@ -235,6 +238,9 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
Cfile_block_list[i].type = CFILE_BLOCK_UNUSED;
}

// Init to an empty string to avoid having to test for NULL everywhere
Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path = vm_strdup("");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This memory is leaked. This can be seen in the valgrind results of the unit tests.


// 32 bit CRC table init
cf_chksum_long_init();

Expand Down Expand Up @@ -1120,6 +1126,43 @@ int cf_get_dir_type(CFILE *cfile)
return Cfile_block_list[cfile->id].dir_type;
}

/**
* Stuffs Pathtypes with an additional path leading to a subdir of the same name as the given file (minus file extension).
* Currently used for allowing frames of .eff animations to be found in their own subdirectories.
*
* Example: if called with "debris.eff" and that file is in data/maps, then Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path
* will be stuffed with data/maps/debris, allowing data/maps/debris/debris_0000.dds (etc) to be found
*/
bool cf_set_temp_subdir_pathtype(const char *filename) {
mprintf(("CFILE: Setting temporary pathtype for %s... ", filename));

// Finds the relative path of where the file exists and appends the filename
// (without extension) to it, giving us a relative path that can be temporarily
// stuffed into Pathtypes
for (size_t i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++) {
if (cf_find_file_location(filename, i, 0, NULL, NULL, NULL)) {
SCP_string subdir, finalpath;

subdir = SCP_string(filename);
subdir = subdir.substr(0, subdir.find_last_of("."));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If filename doesn't contain an extension then will find_last_of will return a value that is not valid for substr.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't specifically test it, but according to documentation it'll return string::npos meaning that substr will just return the complete string.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, well that's convenient.


finalpath = SCP_string(Pathtypes[i].path);
finalpath += DIR_SEPARATOR_STR + subdir;

vm_free(Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path);

Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path = vm_strdup(finalpath.c_str());

mprintf(("OK. Temporary pathtype is now %s\n", Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path));

return true;
}
}

mprintf(("Failed! File %s not found!\n", filename));
return false;
}

// cf_returndata() returns the data pointer for a memory-mapped file that is associated
// with the CFILE structure passed as a parameter
//
Expand Down
7 changes: 6 additions & 1 deletion code/cfile/cfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ typedef struct {
#define CF_TYPE_INTEL_ANIMS 34
#define CF_TYPE_SCRIPTS 35
#define CF_TYPE_FICTION 36
#define CF_TYPE_TEMP_SUBDIR_LOOKUP 37

#define CF_MAX_PATH_TYPES 37 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
#define CF_MAX_PATH_TYPES 38 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES


// TRUE if type is specified and valid
Expand Down Expand Up @@ -129,6 +130,10 @@ char *cf_add_ext(const char *filename, const char *ext);
// return CF_TYPE (directory location type) of a CFILE you called cfopen() successfully on.
int cf_get_dir_type(CFILE *cfile);

/**
* @brief Stuffs Pathtypes with an additional path leading to a subdir of the same name as the given file (minus file extension)
*/
bool cf_set_temp_subdir_pathtype(const char *filename);

// Opens the file. If no path is given, use the extension to look into the
// default path. If mode is NULL, delete the file.
Expand Down
7 changes: 7 additions & 0 deletions code/cfile/cfilesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,12 @@ void cf_search_root_pack(int root_index)
strcat_s( search_path, DIR_SEPARATOR_STR );
}
strcat_s( search_path, find.filename );

// If this directory is a subdir containing for example .eff frames,
// then those files won't be found (below) by just checking all the
// standard paths, so we temporarily add this directory to Pathtypes
vm_free(Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path);
Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path = vm_strdup(search_path);
}

//mprintf(( "Current dir = '%s'\n", search_path ));
Expand Down Expand Up @@ -911,6 +917,7 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
case CF_TYPE_MULTI_CACHE:
case CF_TYPE_MISSIONS:
case CF_TYPE_CACHE:
case CF_TYPE_TEMP_SUBDIR_LOOKUP:
cfs_slow_search = 1;
break;

Expand Down
8 changes: 7 additions & 1 deletion code/graphics/generic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,19 @@ int generic_anim_stream(generic_anim *ga, const bool cache)
ga->bitmap_id = bm_create(ga->png.anim->bpp, ga->width, ga->height, ga->buffer, 0);
}
else {
bool in_subdir;
bpp = 32;
if(ga->use_hud_color)
bpp = 8;
bm_load_and_parse_eff(ga->filename, CF_TYPE_ANY, &ga->num_frames, &anim_fps, &ga->keyframe, 0);
bm_load_and_parse_eff(ga->filename, CF_TYPE_ANY, &ga->num_frames, &anim_fps, &ga->keyframe, 0, &in_subdir);
char *p = strrchr( ga->filename, '.' );
if ( p )
*p = 0;

if (in_subdir) {
cf_set_temp_subdir_pathtype(ga->filename);
}

char frame_name[MAX_FILENAME_LEN];
snprintf(frame_name, MAX_FILENAME_LEN, "%s_0000", ga->filename);
ga->bitmap_id = bm_load(frame_name);
Expand Down