Skip to content

Commit 6a502eb

Browse files
committed
Added $Subdir: <bool> .eff file property
This allows animation frames of eff animations to be located in a subdirectory. This is useful for de-cluttering the effects directory in particular.
1 parent 20a22e6 commit 6a502eb

7 files changed

Lines changed: 110 additions & 10 deletions

File tree

‎code/bmpman/bm_internal.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ union bm_extra_info {
3636
// stuff for static animations
3737
BM_TYPE type; //!< type for individual images
3838
char filename[MAX_FILENAME_LEN]; //!< filename for individual images
39+
bool in_subdir; //!< Whether frames are in their own subdirectory
3940
} eff;
4041
struct {
4142
bool is_apng; //!< Is this animation an APNG?

‎code/bmpman/bmpman.cpp‎

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "pngutils/pngutils.h"
3636
#include "ship/ship.h"
3737
#include "tgautils/tgautils.h"
38+
#include "cfile/cfilesystem.h"
3839

3940
#include <ctype.h>
4041
#include <limits.h>
@@ -47,7 +48,20 @@
4748
/**
4849
* @todo upgrade this to an inline funciton, taking bitmap_entry and const char* as arguments
4950
*/
50-
#define EFF_FILENAME_CHECK { if ( be->type == BM_TYPE_EFF ) strcpy_s( filename, be->info.ani.eff.filename ); else strcpy_s( filename, be->filename ); }
51+
#define EFF_FILENAME_CHECK \
52+
{ \
53+
if ( be->type == BM_TYPE_EFF ) { \
54+
strcpy_s( filename, be->info.ani.eff.filename ); \
55+
if (be->info.ani.eff.in_subdir) { \
56+
if (!cf_set_temp_subdir_pathtype(bm_bitmaps[be->info.ani.first_frame].filename)) { \
57+
mprintf(("BMPMAN: Failed to set temporary pathtype for %s: EFF_FILENAME_CHECK failed!\n", be->filename)); \
58+
} \
59+
} \
60+
} \
61+
else { \
62+
strcpy_s( filename, be->filename ); \
63+
} \
64+
}
5165
// --------------------------------------------------------------------------------------------------------------------
5266
// Monitor variables
5367
MONITOR(NumBitmapPage)
@@ -83,6 +97,8 @@ const int BM_ANI_NUM_TYPES = sizeof(bm_ani_type_list) / sizeof(bm_ani_type_list[
8397
void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
8498
void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
8599

100+
extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
101+
86102
// --------------------------------------------------------------------------------------------------------------------
87103
// Declaration of protected variables (defined in cmdline.cpp).
88104
extern int Cmdline_cache_bitmaps;
@@ -1311,8 +1327,9 @@ int bm_load(const SCP_string& filename) {
13111327
return bm_load(filename.c_str());
13121328
}
13131329

1314-
bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type) {
1330+
bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type, bool *in_subdir) {
13151331
int frames = 0, fps = 30, keyframe = 0;
1332+
bool subdir = false;
13161333
char ext[8];
13171334
BM_TYPE c_type = BM_TYPE_NONE;
13181335
char file_text[1024];
@@ -1350,6 +1367,10 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
13501367
return false;
13511368
}
13521369

1370+
if (optional_string( "$Subdir:" )) {
1371+
stuff_boolean(&subdir);
1372+
}
1373+
13531374
// done with EFF so unpause parsing so whatever can continue
13541375
unpause_parse();
13551376

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

1410+
*in_subdir = subdir;
1411+
13891412
return true;
13901413
}
13911414

@@ -1501,6 +1524,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
15011524
char filename[MAX_FILENAME_LEN];
15021525
int reduced = 0;
15031526
int anim_fps = 0, anim_frames = 0, key = 0;
1527+
bool in_subdir = false;
15041528
float anim_total_time = 0.0f;
15051529
int anim_width = 0, anim_height = 0;
15061530
BM_TYPE type = BM_TYPE_NONE, eff_type = BM_TYPE_NONE, c_type = BM_TYPE_NONE;
@@ -1597,7 +1621,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
15971621

15981622
// it's an effect file, any readable image type with eff being txt
15991623
if (type == BM_TYPE_EFF) {
1600-
if (!bm_load_and_parse_eff(filename, dir_type, &anim_frames, &anim_fps, &key, &eff_type)) {
1624+
if (!bm_load_and_parse_eff(filename, dir_type, &anim_frames, &anim_fps, &key, &eff_type, &in_subdir)) {
16011625
mprintf(("BMPMAN: Error reading EFF\n"));
16021626
if (img_cfp != nullptr)
16031627
cfclose(img_cfp);
@@ -1695,6 +1719,10 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
16951719
return -1;
16961720
}
16971721

1722+
if (in_subdir) {
1723+
cf_set_temp_subdir_pathtype(filename);
1724+
}
1725+
16981726
int first_handle = bm_get_next_handle();
16991727

17001728
for (i = 0; i < anim_frames; i++) {
@@ -1760,6 +1788,11 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
17601788
bm_bitmaps[n + i].num_mipmaps = mm_lvl;
17611789
bm_bitmaps[n + i].mem_taken = (size_t)img_size;
17621790
bm_bitmaps[n + i].dir_type = dir_type;
1791+
bm_bitmaps[n + i].info.ani.eff.in_subdir = in_subdir;
1792+
if (in_subdir)
1793+
bm_bitmaps[n + i].dir_type = CF_TYPE_TEMP_SUBDIR_LOOKUP;
1794+
else
1795+
bm_bitmaps[n + i].dir_type = dir_type;
17631796

17641797
bm_bitmaps[n + i].load_count++;
17651798

@@ -2594,6 +2627,10 @@ void bm_page_in_stop() {
25942627
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)) {
25952628
if (bm_bitmaps[i].preloaded) {
25962629
if (bm_preloading) {
2630+
if (bm_bitmaps[i].type == BM_TYPE_EFF && bm_bitmaps[i].info.ani.eff.in_subdir) {
2631+
cf_set_temp_subdir_pathtype(bm_bitmaps[i].filename);
2632+
}
2633+
25972634
if (!gr_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded == 2))) {
25982635
mprintf(("Out of VRAM. Done preloading.\n"));
25992636
bm_preloading = 0;

‎code/bmpman/bmpman.h‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -676,15 +676,16 @@ bool bm_set_render_target(int handle, int face = -1);
676676
*
677677
* @param[in] filename The filename of the .EFF
678678
* @param[in] dir_type
679-
* @param[out] nframes (optional) If given, is set to the number of frames this .EFF has
680-
* @param[out] nfps (optional) If given, is set to the fps of this .EFF
681-
* @param[out] key (optional) If given, is set to the keyframe index of this .EFF
682-
* @param[out] type (optional) If given, is set to the BM_TYPE of the .EFF
679+
* @param[out] nframes (optional) If given, is set to the number of frames this .EFF has
680+
* @param[out] nfps (optional) If given, is set to the fps of this .EFF
681+
* @param[out] key (optional) If given, is set to the keyframe index of this .EFF
682+
* @param[out] type (optional) If given, is set to the BM_TYPE of the .EFF
683+
* @param[out] in_subdir (optional) If given, is set to true if the frames of this .EFF are in a subdir
683684
*
684685
* @returns true If successful
685686
* @returns false If not successful
686687
*/
687-
bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type);
688+
bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, BM_TYPE *type, bool *in_subdir);
688689

689690
/**
690691
* @brief Calculates & returns the current frame of an animation

‎code/cfile/cfile.cpp‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
8888
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
8989
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA },
9090
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
91+
{ CF_TYPE_TEMP_SUBDIR_LOOKUP, NULL, ".pcx .tga .jpg .png .dds", CF_TYPE_DATA },
9192
};
9293

9394

@@ -135,6 +136,8 @@ void cfile_close()
135136

136137
cf_free_secondary_filelist();
137138

139+
vm_free(Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path);
140+
138141
cfile_inited = 0;
139142
}
140143

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

241+
// Init to an empty string to avoid having to test for NULL everywhere
242+
Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path = vm_strdup("");
243+
238244
// 32 bit CRC table init
239245
cf_chksum_long_init();
240246

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

1129+
/**
1130+
* Stuffs Pathtypes with an additional path leading to a subdir of the same name as the given file (minus file extension).
1131+
* Currently used for allowing frames of .eff animations to be found in their own subdirectories.
1132+
*
1133+
* Example: if called with "debris.eff" and that file is in data/maps, then Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path
1134+
* will be stuffed with data/maps/debris, allowing data/maps/debris/debris_0000.dds (etc) to be found
1135+
*/
1136+
bool cf_set_temp_subdir_pathtype(const char *filename) {
1137+
mprintf(("CFILE: Setting temporary pathtype for %s... ", filename));
1138+
1139+
// Finds the relative path of where the file exists and appends the filename
1140+
// (without extension) to it, giving us a relative path that can be temporarily
1141+
// stuffed into Pathtypes
1142+
for (size_t i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++) {
1143+
if (cf_find_file_location(filename, i, 0, NULL, NULL, NULL)) {
1144+
SCP_string subdir, finalpath;
1145+
1146+
subdir = SCP_string(filename);
1147+
subdir = subdir.substr(0, subdir.find_last_of("."));
1148+
1149+
finalpath = SCP_string(Pathtypes[i].path);
1150+
finalpath += DIR_SEPARATOR_STR + subdir;
1151+
1152+
vm_free(Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path);
1153+
1154+
Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path = vm_strdup(finalpath.c_str());
1155+
1156+
mprintf(("OK. Temporary pathtype is now %s\n", Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path));
1157+
1158+
return true;
1159+
}
1160+
}
1161+
1162+
mprintf(("Failed! File %s not found!\n", filename));
1163+
return false;
1164+
}
1165+
11231166
// cf_returndata() returns the data pointer for a memory-mapped file that is associated
11241167
// with the CFILE structure passed as a parameter
11251168
//

‎code/cfile/cfile.h‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ typedef struct {
7878
#define CF_TYPE_INTEL_ANIMS 34
7979
#define CF_TYPE_SCRIPTS 35
8080
#define CF_TYPE_FICTION 36
81+
#define CF_TYPE_TEMP_SUBDIR_LOOKUP 37
8182

82-
#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
83+
#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
8384

8485

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

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

133138
// Opens the file. If no path is given, use the extension to look into the
134139
// default path. If mode is NULL, delete the file.

‎code/cfile/cfilesystem.cpp‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,12 @@ void cf_search_root_pack(int root_index)
725725
strcat_s( search_path, DIR_SEPARATOR_STR );
726726
}
727727
strcat_s( search_path, find.filename );
728+
729+
// If this directory is a subdir containing for example .eff frames,
730+
// then those files won't be found (below) by just checking all the
731+
// standard paths, so we temporarily add this directory to Pathtypes
732+
vm_free(Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path);
733+
Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path = vm_strdup(search_path);
728734
}
729735

730736
//mprintf(( "Current dir = '%s'\n", search_path ));
@@ -911,6 +917,7 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
911917
case CF_TYPE_MULTI_CACHE:
912918
case CF_TYPE_MISSIONS:
913919
case CF_TYPE_CACHE:
920+
case CF_TYPE_TEMP_SUBDIR_LOOKUP:
914921
cfs_slow_search = 1;
915922
break;
916923

‎code/graphics/generic.cpp‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,19 @@ int generic_anim_stream(generic_anim *ga, const bool cache)
242242
ga->bitmap_id = bm_create(ga->png.anim->bpp, ga->width, ga->height, ga->buffer, 0);
243243
}
244244
else {
245+
bool in_subdir;
245246
bpp = 32;
246247
if(ga->use_hud_color)
247248
bpp = 8;
248-
bm_load_and_parse_eff(ga->filename, CF_TYPE_ANY, &ga->num_frames, &anim_fps, &ga->keyframe, 0);
249+
bm_load_and_parse_eff(ga->filename, CF_TYPE_ANY, &ga->num_frames, &anim_fps, &ga->keyframe, 0, &in_subdir);
249250
char *p = strrchr( ga->filename, '.' );
250251
if ( p )
251252
*p = 0;
253+
254+
if (in_subdir) {
255+
cf_set_temp_subdir_pathtype(ga->filename);
256+
}
257+
252258
char frame_name[MAX_FILENAME_LEN];
253259
snprintf(frame_name, MAX_FILENAME_LEN, "%s_0000", ga->filename);
254260
ga->bitmap_id = bm_load(frame_name);

0 commit comments

Comments
 (0)