Skip to content

Commit aae2020

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 9f60839 commit aae2020

7 files changed

Lines changed: 118 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: 41 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 (!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,11 @@ 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+
1374+
13531375
// done with EFF so unpause parsing so whatever can continue
13541376
unpause_parse();
13551377

@@ -1386,6 +1408,8 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
13861408
if (key)
13871409
*key = keyframe;
13881410

1411+
*in_subdir = subdir;
1412+
13891413
return true;
13901414
}
13911415

@@ -1501,6 +1525,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
15011525
char filename[MAX_FILENAME_LEN];
15021526
int reduced = 0;
15031527
int anim_fps = 0, anim_frames = 0, key = 0;
1528+
bool in_subdir = false;
15041529
float anim_total_time = 0.0f;
15051530
int anim_width = 0, anim_height = 0;
15061531
BM_TYPE type = BM_TYPE_NONE, eff_type = BM_TYPE_NONE, c_type = BM_TYPE_NONE;
@@ -1597,7 +1622,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
15971622

15981623
// it's an effect file, any readable image type with eff being txt
15991624
if (type == BM_TYPE_EFF) {
1600-
if (!bm_load_and_parse_eff(filename, dir_type, &anim_frames, &anim_fps, &key, &eff_type)) {
1625+
if (!bm_load_and_parse_eff(filename, dir_type, &anim_frames, &anim_fps, &key, &eff_type, &in_subdir)) {
16011626
mprintf(("BMPMAN: Error reading EFF\n"));
16021627
if (img_cfp != nullptr)
16031628
cfclose(img_cfp);
@@ -1695,6 +1720,10 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
16951720
return -1;
16961721
}
16971722

1723+
if (in_subdir) {
1724+
set_temp_subdir_pathtype(filename);
1725+
}
1726+
16981727
int first_handle = bm_get_next_handle();
16991728

17001729
for (i = 0; i < anim_frames; i++) {
@@ -1760,6 +1789,11 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
17601789
bm_bitmaps[n + i].num_mipmaps = mm_lvl;
17611790
bm_bitmaps[n + i].mem_taken = (size_t)img_size;
17621791
bm_bitmaps[n + i].dir_type = dir_type;
1792+
bm_bitmaps[n + i].info.ani.eff.in_subdir = in_subdir;
1793+
if (in_subdir)
1794+
bm_bitmaps[n + i].dir_type = CF_TYPE_TEMP_SUBDIR_LOOKUP;
1795+
else
1796+
bm_bitmaps[n + i].dir_type = dir_type;
17631797

17641798
bm_bitmaps[n + i].load_count++;
17651799

@@ -2594,6 +2628,10 @@ void bm_page_in_stop() {
25942628
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)) {
25952629
if (bm_bitmaps[i].preloaded) {
25962630
if (bm_preloading) {
2631+
if (bm_bitmaps[i].type == BM_TYPE_EFF && bm_bitmaps[i].info.ani.eff.in_subdir) {
2632+
set_temp_subdir_pathtype(bm_bitmaps[i].filename);
2633+
}
2634+
25972635
if (!gr_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded == 2))) {
25982636
mprintf(("Out of VRAM. Done preloading.\n"));
25992637
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: 56 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, ".eff", 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,56 @@ 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 set_temp_subdir_pathtype(const char *filename) {
1137+
// Gets the absolute path of the file, removes the part that is identical with the
1138+
// absolute root path and appends the filename to it (without extension), giving us
1139+
// a relative path that can be temporarily stuffed into Pathtypes so the frames can be found
1140+
1141+
char fullpath[MAX_PATH]; // Absolute path to the given file
1142+
char fullrootpath[MAX_PATH]; // Absolute root path
1143+
size_t size, offset; // Needed for cf_find_file_location, but not used
1144+
1145+
cf_create_default_path_string(fullrootpath, sizeof(fullrootpath) - 1, CF_TYPE_ROOT, NULL);
1146+
if (!cf_find_file_location(filename, CF_TYPE_ANY, sizeof(fullpath)-1, fullpath, &size, &offset)) {
1147+
mprintf(("CFILE: Failed to set temporary pathtype for %s: file not found!\n", filename));
1148+
return false;
1149+
}
1150+
1151+
Assertion(strlen(fullpath) < strlen(fullrootpath), "Path to %s was shorter than the root path:\n%s\n%s\n", filename, fullpath, fullrootpath);
1152+
1153+
mprintf(("CFILE: Setting temporary pathtype for %s... ", filename));
1154+
1155+
char *trimmed_path; // The differing portion of fullpath and fullrootpath
1156+
trimmed_path = &fullpath[strlen(fullrootpath)];
1157+
1158+
char *extpos = strstr(trimmed_path, "."); // Where the file extension begins
1159+
char basepath[MAX_PATH]; // This will hold the final, relative path
1160+
1161+
Assertion(extpos != NULL, "Tried to set temporary pathtype based on filename without extension: %s\n", filename);
1162+
1163+
// Copy the relative path of the given file to basepath, excluding the extension
1164+
strncpy(basepath, trimmed_path, extpos-trimmed_path);
1165+
1166+
// Make sure it's null-terminated right
1167+
basepath[extpos-trimmed_path] = '\0';
1168+
1169+
// Free the previous string first
1170+
vm_free(Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path);
1171+
1172+
Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path = vm_strdup(basepath);
1173+
1174+
mprintf(("OK. Temporary pathtype is now %s.\n", Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path));
1175+
1176+
return true;
1177+
}
1178+
11231179
// cf_returndata() returns the data pointer for a memory-mapped file that is associated
11241180
// with the CFILE structure passed as a parameter
11251181
//

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 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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
911911
case CF_TYPE_MULTI_CACHE:
912912
case CF_TYPE_MISSIONS:
913913
case CF_TYPE_CACHE:
914+
case CF_TYPE_TEMP_SUBDIR_LOOKUP:
914915
cfs_slow_search = 1;
915916
break;
916917

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+
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)