animlist support
parent
99d6884984
commit
380732c4ad
|
@ -15418,8 +15418,8 @@ API const char * xml_string(char *key);
|
|||
API unsigned xml_count(char *key);
|
||||
API array(char) xml_blob(char *key);
|
||||
#define xml_string(...) xml_string(va(__VA_ARGS__)) // syntax sugar: string
|
||||
#define xml_int(...) atoi(xml_string(va(__VA_ARGS__))) // syntax sugar: int
|
||||
#define xml_float(...) atof(xml_string(va(__VA_ARGS__))) // syntax sugar: float
|
||||
#define xml_int(...) atoi(xml_string(__VA_ARGS__)) // syntax sugar: int
|
||||
#define xml_float(...) atof(xml_string(__VA_ARGS__)) // syntax sugar: float
|
||||
#define xml_blob(...) xml_blob(va(__VA_ARGS__)) // syntax sugar: base64 blob
|
||||
#define xml_count(...) xml_count(va(__VA_ARGS__)) // syntax sugar: count nodes
|
||||
API void xml_pop();
|
||||
|
@ -331929,31 +331929,42 @@ const char *COOK_INI = "tools/cook.ini";
|
|||
static unsigned ART_SKIP_ROOT; // number of chars to skip the base root in ART folder
|
||||
static unsigned ART_LEN; // dupe
|
||||
|
||||
typedef struct cook_script_t {
|
||||
char *infile; // free after use
|
||||
char *finalfile; // free after use. can be either infile or a totally different file
|
||||
typedef struct cook_subscript_t {
|
||||
char *infile;
|
||||
char *outfile; // can be either infile, or a totally different file
|
||||
char *script;
|
||||
char *outname;
|
||||
int compress_level;
|
||||
} cook_subscript_t;
|
||||
|
||||
typedef struct cook_script_t {
|
||||
cook_subscript_t cs[8];
|
||||
|
||||
int num_passes;
|
||||
} cook_script_t;
|
||||
|
||||
static
|
||||
cook_script_t cook_script(const char *rules, const char *infile, const char *outfile) {
|
||||
cook_script_t mcs = { 0 };
|
||||
|
||||
// pass loop: some asset rules may require multiple cook passes
|
||||
for( int pass = 0; pass < countof(mcs.cs); ++pass ) {
|
||||
// by default, assume:
|
||||
// - no script is going to be generated (empty script)
|
||||
// - if no script is going to be generated, output is in fact input file.
|
||||
// - no compression is going to be required.
|
||||
cook_script_t cs = { 0 };
|
||||
cook_subscript_t cs = { 0 };
|
||||
|
||||
// reuse script heap from last call if possible (optimization)
|
||||
static __thread char *script = 0;
|
||||
if(script) script[0] = 0;
|
||||
|
||||
// reuse parsing maps if possible (optimization)
|
||||
static __thread map(char*, char*) symbols = 0;
|
||||
static __thread map(char*, char*) groups = 0;
|
||||
|
||||
if(!symbols) map_init(symbols, less_str, hash_str);
|
||||
if(!groups) map_init(groups, less_str, hash_str);
|
||||
static __thread map(char*, char*) symbols = 0; if(!symbols) map_init_str(symbols);
|
||||
static __thread map(char*, char*) groups = 0; if(!groups) map_init_str(groups);
|
||||
static __thread set(char*) passes = 0; if(!passes) set_init_str(passes);
|
||||
map_clear(symbols);
|
||||
map_clear(groups);
|
||||
|
||||
map_find_or_add(symbols, "INFILE", STRDUP(infile));
|
||||
map_find_or_add(symbols, "INPUT", STRDUP(infile));
|
||||
|
@ -331963,6 +331974,9 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
map_find_or_add(symbols, "EDITOR", STRDUP(EDITOR));
|
||||
map_find_or_add(symbols, "PROGRESS", STRDUP(va("%03d", cook_progress())));
|
||||
|
||||
// clear pass counter
|
||||
set_clear(passes);
|
||||
|
||||
// start parsing. parsing is enabled by default
|
||||
int enabled = 1;
|
||||
array(char*)lines = strsplit(rules, "\r\n");
|
||||
|
@ -331997,11 +332011,11 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
if( eos ) *eos = 0;
|
||||
|
||||
// replace all symbols
|
||||
char* nl = STRDUP(line);
|
||||
char* nl = STRDUP(line); // @leak
|
||||
for each_map(symbols, char*, key, char*, val) {
|
||||
strrepl(&nl, key, val);
|
||||
}
|
||||
lines[i] = line = nl; // @fixme:leak
|
||||
lines[i] = line = nl;
|
||||
|
||||
static thread_mutex_t lock, *init = 0; if(!init) thread_mutex_init(init = &lock);
|
||||
thread_mutex_lock( &lock );
|
||||
|
@ -332015,9 +332029,9 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
enabled = 1;
|
||||
int is_cook = !!strstr(line, "[cook]");
|
||||
int is_compress = !!strstr(line, "[compress]");
|
||||
if( !is_cook && !is_compress ) {
|
||||
if( !is_cook && !is_compress ) { // if not a special section...
|
||||
// remove hint cook tag if present. that's informative only.
|
||||
if(strbegi(line, "[cook ") ) memcpy(line+1, " ", 4);
|
||||
if(strbegi(line, "[cook ") ) memcpy(line+1, " ", 4); // line += 6;
|
||||
|
||||
// start parsing expressions like `[media && !avi && mp3]`
|
||||
array(char*) tags = strsplit(line, " []&");
|
||||
|
@ -332026,8 +332040,9 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
char **INPUT = map_find(symbols, "INPUT");
|
||||
bool found_in_set = true;
|
||||
|
||||
for( int i = 0, end = array_count(tags); i < end; ++i) { char *tag = tags[i];
|
||||
for( int i = 0, end = array_count(tags); i < end; ++i) {
|
||||
bool negate = false;
|
||||
char *tag = tags[i];
|
||||
while(*tag == '!') negate ^= 1, ++tag;
|
||||
|
||||
// find tag in groups map
|
||||
|
@ -332037,7 +332052,7 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
char *list = *is_group;
|
||||
char *INPUT_EXT = file_ext(infile); INPUT_EXT = strrchr(INPUT_EXT, '.'); // .ext1.ext -> .ext
|
||||
char *ext = INPUT_EXT; ext += ext[0] == '.'; // dotless
|
||||
bool in_list = strbegi(list, ext) || strstri(list, va(",%s,",ext)) || strendi(list, va(",%s",ext));
|
||||
bool in_list = strbegi(list, ext) || strendi(list, va(",%s",ext)) || strstri(list, va(",%s,",ext));
|
||||
if( !in_list ^ negate ) { found_in_set = false; break; }
|
||||
} else {
|
||||
char *ext = va(".%s", tag);
|
||||
|
@ -332045,6 +332060,13 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
if( !found ^ negate ) { found_in_set = false; break; }
|
||||
}
|
||||
}
|
||||
if( found_in_set ) {
|
||||
// inc pass
|
||||
set_find_or_add(passes, STRDUP(*tags)); // @leak
|
||||
// check whether we keep searching
|
||||
int num_passes = set_count(passes);
|
||||
found_in_set = ( pass == (num_passes-1) );
|
||||
}
|
||||
//
|
||||
enabled = found_in_set ? 1 : 0;
|
||||
}
|
||||
|
@ -332085,20 +332107,26 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
int errorlevel = has_errorlevel ? atoi(has_errorlevel + 2) : 0;
|
||||
if( has_errorlevel ) memcpy(has_errorlevel, " ", 3);
|
||||
|
||||
// detect if newer extension is present, and thus update OUTPUT if needed
|
||||
// detect if newer extension or filename is present, and thus update OUTPUT if needed
|
||||
char *newer_extension = strstr(line, "->"); if(newer_extension) {
|
||||
*newer_extension = 0;
|
||||
newer_extension += 2 + strspn(newer_extension + 2, " ");
|
||||
|
||||
if( strchr(newer_extension, '.') ) {
|
||||
// newer filename
|
||||
cs.outname = stringf("%s@%s", cs.outname ? cs.outname : infile, newer_extension); // @leak
|
||||
newer_extension = NULL;
|
||||
} else {
|
||||
strcatf(&*OUTPUT, ".%s", newer_extension);
|
||||
}
|
||||
}
|
||||
|
||||
// replace all symbols
|
||||
char* nl = STRDUP(line);
|
||||
char* nl = STRDUP(line); // @leak
|
||||
for each_map(symbols, char*, key, char*, val) {
|
||||
strrepl(&nl, key, val);
|
||||
}
|
||||
lines[i] = line = nl; // @fixme:leak
|
||||
lines[i] = line = nl;
|
||||
|
||||
// convert slashes
|
||||
ifdef(win32,
|
||||
|
@ -332123,43 +332151,41 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
}
|
||||
}
|
||||
|
||||
// compression
|
||||
char* ext = file_ext(infile); ext = strrchr(ext, '.'); ext += ext[0] == '.'; // dotless INPUT_EXT
|
||||
|
||||
char** OUTPUT = map_find(symbols, "OUTPUT");
|
||||
int ext_num_groups = 0;
|
||||
|
||||
// compression
|
||||
if( 1 ) {
|
||||
char* ext = file_ext(infile); ext = strrchr(ext, '.'); ext += ext[0] == '.'; // dotless INPUT_EXT
|
||||
char* belongs_to = 0;
|
||||
for each_map(groups, char*, key, char*, val) {
|
||||
if( !isdigit(key[0]) ) {
|
||||
char *comma = va(",%s,", ext);
|
||||
if( strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
if( !strcmpi(val,ext) || strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
belongs_to = key;
|
||||
//goto break1; // each_map() macro is made of multiple for(;;)s. goto needed; you cant escape with single break.
|
||||
ext_num_groups++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break1:;
|
||||
char *compression = 0;
|
||||
for each_map(groups, char*, key, char*, val) {
|
||||
if( isdigit(key[0]) ) {
|
||||
char *comma = va(",%s,", ext);
|
||||
if( strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
if( !strcmpi(val,ext) || strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
compression = key;
|
||||
//goto break2; // each_map() macro is made of multiple for(;;)s. goto needed; you cant escape with single break.
|
||||
}
|
||||
comma = va(",%s,", belongs_to);
|
||||
if( strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
if( !strcmpi(val,ext) || strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
compression = key;
|
||||
//goto break2; // each_map() macro is made of multiple for(;;)s. goto needed; you cant escape with single break.
|
||||
}
|
||||
}
|
||||
}
|
||||
break2:;
|
||||
|
||||
cs.compress_level = 0;
|
||||
if( compression ) {
|
||||
// last chance to optionally override the compressor at command-line level
|
||||
static const char *compressor_override, **init = 0;
|
||||
if( !init ) *(init = &compressor_override) = option("--cook-compressor", "");
|
||||
static const char *compressor_override;
|
||||
do_once compressor_override = option("--cook-compressor", "");
|
||||
if( compressor_override[0] ) compression = (char*)compressor_override;
|
||||
|
||||
/**/ if(strstri(compression, "PPP")) cs.compress_level = atoi(compression) | PPP;
|
||||
|
@ -332175,11 +332201,12 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
else if(strstri(compression, "BCM")) cs.compress_level = atoi(compression) | BCM;
|
||||
else cs.compress_level = isdigit(compression[0]) ? atoi(compression) : 6 /*| DEFL*/;
|
||||
}
|
||||
}
|
||||
|
||||
// if script was generated...
|
||||
if( script && script[0]) {
|
||||
// update outfile
|
||||
cs.finalfile = *OUTPUT;
|
||||
cs.outfile = *OUTPUT;
|
||||
|
||||
// amalgamate script
|
||||
array(char*) lines = strsplit(script, "\r\n");
|
||||
|
@ -332202,15 +332229,22 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
} else {
|
||||
// ... else bypass infile->outfile
|
||||
char** INFILE = map_find(symbols, "INFILE");
|
||||
cs.finalfile = *INFILE;
|
||||
cs.outfile = *INFILE;
|
||||
|
||||
// and return an empty script
|
||||
cs.script = "";
|
||||
}
|
||||
|
||||
map_clear(symbols);
|
||||
map_clear(groups);
|
||||
return cs;
|
||||
cs.outname = cs.outname ? cs.outname : (char*)infile;
|
||||
|
||||
ASSERT(mcs.num_passes < countof(mcs.cs));
|
||||
mcs.cs[mcs.num_passes++] = cs;
|
||||
|
||||
bool next_pass_required = mcs.num_passes < ext_num_groups;
|
||||
if( !next_pass_required ) break;
|
||||
}
|
||||
|
||||
return mcs;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -332372,56 +332406,53 @@ int cook(void *userdata) {
|
|||
*progress = ((i+1) == end ? 90 : (i * 90) / end); // (i+i>0) * 100.f / end;
|
||||
|
||||
// start cook
|
||||
const char *fname = uncooked[i]; //job->files[j];
|
||||
int inlen = file_size(fname);
|
||||
const char *infile = uncooked[i]; //job->files[j];
|
||||
int inlen = file_size(infile);
|
||||
|
||||
// generate a cooking script for this asset
|
||||
cook_script_t cs = cook_script(job->rules, fname, COOK_TMPFILE);
|
||||
cook_script_t mcs = cook_script(job->rules, infile, COOK_TMPFILE);
|
||||
// puts(cs.script);
|
||||
|
||||
for(int pass = 0; pass < mcs.num_passes; ++pass) {
|
||||
cook_subscript_t cs = mcs.cs[pass];
|
||||
|
||||
// log to batch file for forensic purposes, if explicitly requested
|
||||
static __thread bool logging = 0, *init = 0; if(!init) *(init = &logging) = !!flag("--cook-debug") || cook_debug;
|
||||
static __thread bool logging = 0; do_once logging = !!flag("--cook-debug") || cook_debug;
|
||||
if( logging ) {
|
||||
FILE *logfile = fopen(va("cook%d.cmd",job->threadid), "a+t");
|
||||
if( logfile ) { fprintf(logfile, "@rem %s\n%s\n", fname, cs.script); fclose(logfile); }
|
||||
// maybe log fprintf(logfile, "@rem %*.s\n", 4096, app_exec_output()); ?
|
||||
if( logfile ) { fprintf(logfile, "@rem %s\n%s\n", cs.outname, cs.script); fclose(logfile); }
|
||||
fprintf(stderr, "%s\n", cs.script);
|
||||
}
|
||||
|
||||
// invoke cooking script and recap status
|
||||
const char *rcout = app_exec(cs.script);
|
||||
int rc = atoi(rcout);
|
||||
int outlen = file_size(cs.finalfile);
|
||||
const char *rc_output = app_exec(cs.script);
|
||||
int rc = atoi(rc_output);
|
||||
int outlen = file_size(cs.outfile);
|
||||
int failed = cs.script[0] ? rc || !outlen : 0;
|
||||
|
||||
// print errors, or...
|
||||
if( failed ) {
|
||||
PRINTF("Import failed: %s while executing:\n%s\nReturned:\n%s\n", fname, cs.script, rcout);
|
||||
PRINTF("Import failed: %s while executing:\n%s\nReturned:\n%s\n", cs.outname, cs.script, rc_output);
|
||||
}
|
||||
// ...process only if included. may include optional compression.
|
||||
else if( cs.compress_level >= 0 ) {
|
||||
FILE *in = fopen(cs.finalfile, "rb");
|
||||
FILE *in = fopen(cs.outfile, "rb");
|
||||
|
||||
#if 0
|
||||
struct stat st; stat(fname, &st);
|
||||
#if 0
|
||||
struct stat st; stat(infile, &st);
|
||||
struct tm *timeinfo = localtime(&st.st_mtime);
|
||||
ASSERT(timeinfo);
|
||||
|
||||
// pretty (truncated) input (C:/prj/V4K/art/file.wav -> file.wav)
|
||||
static __thread int artlen = 0; if(!artlen) artlen = strlen(ART);
|
||||
const char *pretty = fname;
|
||||
if( !strncmp(pretty, ART, artlen) ) pretty += artlen;
|
||||
while(pretty[0] == '/') ++pretty;
|
||||
fname = pretty;
|
||||
//puts(fname);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
char *comment = va("%d", inlen);
|
||||
if( !zip_append_file/*_timeinfo*/(z, fname, comment, in, cs.compress_level/*, timeinfo*/) ) {
|
||||
PANIC("failed to add processed file into %s: %s", zipfile, fname);
|
||||
if( !zip_append_file/*_timeinfo*/(z, cs.outname, comment, in, cs.compress_level/*, timeinfo*/) ) {
|
||||
PANIC("failed to add processed file into %s: %s(%s)", zipfile, cs.outname, infile);
|
||||
}
|
||||
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
zip_close(z);
|
||||
|
|
|
@ -17,31 +17,42 @@ const char *COOK_INI = "tools/cook.ini";
|
|||
static unsigned ART_SKIP_ROOT; // number of chars to skip the base root in ART folder
|
||||
static unsigned ART_LEN; // dupe
|
||||
|
||||
typedef struct cook_script_t {
|
||||
char *infile; // free after use
|
||||
char *finalfile; // free after use. can be either infile or a totally different file
|
||||
typedef struct cook_subscript_t {
|
||||
char *infile;
|
||||
char *outfile; // can be either infile, or a totally different file
|
||||
char *script;
|
||||
char *outname;
|
||||
int compress_level;
|
||||
} cook_subscript_t;
|
||||
|
||||
typedef struct cook_script_t {
|
||||
cook_subscript_t cs[8];
|
||||
|
||||
int num_passes;
|
||||
} cook_script_t;
|
||||
|
||||
static
|
||||
cook_script_t cook_script(const char *rules, const char *infile, const char *outfile) {
|
||||
cook_script_t mcs = { 0 };
|
||||
|
||||
// pass loop: some asset rules may require multiple cook passes
|
||||
for( int pass = 0; pass < countof(mcs.cs); ++pass ) {
|
||||
// by default, assume:
|
||||
// - no script is going to be generated (empty script)
|
||||
// - if no script is going to be generated, output is in fact input file.
|
||||
// - no compression is going to be required.
|
||||
cook_script_t cs = { 0 };
|
||||
cook_subscript_t cs = { 0 };
|
||||
|
||||
// reuse script heap from last call if possible (optimization)
|
||||
static __thread char *script = 0;
|
||||
if(script) script[0] = 0;
|
||||
|
||||
// reuse parsing maps if possible (optimization)
|
||||
static __thread map(char*, char*) symbols = 0;
|
||||
static __thread map(char*, char*) groups = 0;
|
||||
|
||||
if(!symbols) map_init(symbols, less_str, hash_str);
|
||||
if(!groups) map_init(groups, less_str, hash_str);
|
||||
static __thread map(char*, char*) symbols = 0; if(!symbols) map_init_str(symbols);
|
||||
static __thread map(char*, char*) groups = 0; if(!groups) map_init_str(groups);
|
||||
static __thread set(char*) passes = 0; if(!passes) set_init_str(passes);
|
||||
map_clear(symbols);
|
||||
map_clear(groups);
|
||||
|
||||
map_find_or_add(symbols, "INFILE", STRDUP(infile));
|
||||
map_find_or_add(symbols, "INPUT", STRDUP(infile));
|
||||
|
@ -51,6 +62,9 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
map_find_or_add(symbols, "EDITOR", STRDUP(EDITOR));
|
||||
map_find_or_add(symbols, "PROGRESS", STRDUP(va("%03d", cook_progress())));
|
||||
|
||||
// clear pass counter
|
||||
set_clear(passes);
|
||||
|
||||
// start parsing. parsing is enabled by default
|
||||
int enabled = 1;
|
||||
array(char*)lines = strsplit(rules, "\r\n");
|
||||
|
@ -85,11 +99,11 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
if( eos ) *eos = 0;
|
||||
|
||||
// replace all symbols
|
||||
char* nl = STRDUP(line);
|
||||
char* nl = STRDUP(line); // @leak
|
||||
for each_map(symbols, char*, key, char*, val) {
|
||||
strrepl(&nl, key, val);
|
||||
}
|
||||
lines[i] = line = nl; // @fixme:leak
|
||||
lines[i] = line = nl;
|
||||
|
||||
static thread_mutex_t lock, *init = 0; if(!init) thread_mutex_init(init = &lock);
|
||||
thread_mutex_lock( &lock );
|
||||
|
@ -103,9 +117,9 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
enabled = 1;
|
||||
int is_cook = !!strstr(line, "[cook]");
|
||||
int is_compress = !!strstr(line, "[compress]");
|
||||
if( !is_cook && !is_compress ) {
|
||||
if( !is_cook && !is_compress ) { // if not a special section...
|
||||
// remove hint cook tag if present. that's informative only.
|
||||
if(strbegi(line, "[cook ") ) memcpy(line+1, " ", 4);
|
||||
if(strbegi(line, "[cook ") ) memcpy(line+1, " ", 4); // line += 6;
|
||||
|
||||
// start parsing expressions like `[media && !avi && mp3]`
|
||||
array(char*) tags = strsplit(line, " []&");
|
||||
|
@ -114,8 +128,9 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
char **INPUT = map_find(symbols, "INPUT");
|
||||
bool found_in_set = true;
|
||||
|
||||
for( int i = 0, end = array_count(tags); i < end; ++i) { char *tag = tags[i];
|
||||
for( int i = 0, end = array_count(tags); i < end; ++i) {
|
||||
bool negate = false;
|
||||
char *tag = tags[i];
|
||||
while(*tag == '!') negate ^= 1, ++tag;
|
||||
|
||||
// find tag in groups map
|
||||
|
@ -125,7 +140,7 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
char *list = *is_group;
|
||||
char *INPUT_EXT = file_ext(infile); INPUT_EXT = strrchr(INPUT_EXT, '.'); // .ext1.ext -> .ext
|
||||
char *ext = INPUT_EXT; ext += ext[0] == '.'; // dotless
|
||||
bool in_list = strbegi(list, ext) || strstri(list, va(",%s,",ext)) || strendi(list, va(",%s",ext));
|
||||
bool in_list = strbegi(list, ext) || strendi(list, va(",%s",ext)) || strstri(list, va(",%s,",ext));
|
||||
if( !in_list ^ negate ) { found_in_set = false; break; }
|
||||
} else {
|
||||
char *ext = va(".%s", tag);
|
||||
|
@ -133,6 +148,13 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
if( !found ^ negate ) { found_in_set = false; break; }
|
||||
}
|
||||
}
|
||||
if( found_in_set ) {
|
||||
// inc pass
|
||||
set_find_or_add(passes, STRDUP(*tags)); // @leak
|
||||
// check whether we keep searching
|
||||
int num_passes = set_count(passes);
|
||||
found_in_set = ( pass == (num_passes-1) );
|
||||
}
|
||||
//
|
||||
enabled = found_in_set ? 1 : 0;
|
||||
}
|
||||
|
@ -173,20 +195,26 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
int errorlevel = has_errorlevel ? atoi(has_errorlevel + 2) : 0;
|
||||
if( has_errorlevel ) memcpy(has_errorlevel, " ", 3);
|
||||
|
||||
// detect if newer extension is present, and thus update OUTPUT if needed
|
||||
// detect if newer extension or filename is present, and thus update OUTPUT if needed
|
||||
char *newer_extension = strstr(line, "->"); if(newer_extension) {
|
||||
*newer_extension = 0;
|
||||
newer_extension += 2 + strspn(newer_extension + 2, " ");
|
||||
|
||||
if( strchr(newer_extension, '.') ) {
|
||||
// newer filename
|
||||
cs.outname = stringf("%s@%s", cs.outname ? cs.outname : infile, newer_extension); // @leak
|
||||
newer_extension = NULL;
|
||||
} else {
|
||||
strcatf(&*OUTPUT, ".%s", newer_extension);
|
||||
}
|
||||
}
|
||||
|
||||
// replace all symbols
|
||||
char* nl = STRDUP(line);
|
||||
char* nl = STRDUP(line); // @leak
|
||||
for each_map(symbols, char*, key, char*, val) {
|
||||
strrepl(&nl, key, val);
|
||||
}
|
||||
lines[i] = line = nl; // @fixme:leak
|
||||
lines[i] = line = nl;
|
||||
|
||||
// convert slashes
|
||||
ifdef(win32,
|
||||
|
@ -211,43 +239,41 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
}
|
||||
}
|
||||
|
||||
// compression
|
||||
char* ext = file_ext(infile); ext = strrchr(ext, '.'); ext += ext[0] == '.'; // dotless INPUT_EXT
|
||||
|
||||
char** OUTPUT = map_find(symbols, "OUTPUT");
|
||||
int ext_num_groups = 0;
|
||||
|
||||
// compression
|
||||
if( 1 ) {
|
||||
char* ext = file_ext(infile); ext = strrchr(ext, '.'); ext += ext[0] == '.'; // dotless INPUT_EXT
|
||||
char* belongs_to = 0;
|
||||
for each_map(groups, char*, key, char*, val) {
|
||||
if( !isdigit(key[0]) ) {
|
||||
char *comma = va(",%s,", ext);
|
||||
if( strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
if( !strcmpi(val,ext) || strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
belongs_to = key;
|
||||
//goto break1; // each_map() macro is made of multiple for(;;)s. goto needed; you cant escape with single break.
|
||||
ext_num_groups++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break1:;
|
||||
char *compression = 0;
|
||||
for each_map(groups, char*, key, char*, val) {
|
||||
if( isdigit(key[0]) ) {
|
||||
char *comma = va(",%s,", ext);
|
||||
if( strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
if( !strcmpi(val,ext) || strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
compression = key;
|
||||
//goto break2; // each_map() macro is made of multiple for(;;)s. goto needed; you cant escape with single break.
|
||||
}
|
||||
comma = va(",%s,", belongs_to);
|
||||
if( strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
if( !strcmpi(val,ext) || strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
compression = key;
|
||||
//goto break2; // each_map() macro is made of multiple for(;;)s. goto needed; you cant escape with single break.
|
||||
}
|
||||
}
|
||||
}
|
||||
break2:;
|
||||
|
||||
cs.compress_level = 0;
|
||||
if( compression ) {
|
||||
// last chance to optionally override the compressor at command-line level
|
||||
static const char *compressor_override, **init = 0;
|
||||
if( !init ) *(init = &compressor_override) = option("--cook-compressor", "");
|
||||
static const char *compressor_override;
|
||||
do_once compressor_override = option("--cook-compressor", "");
|
||||
if( compressor_override[0] ) compression = (char*)compressor_override;
|
||||
|
||||
/**/ if(strstri(compression, "PPP")) cs.compress_level = atoi(compression) | PPP;
|
||||
|
@ -263,11 +289,12 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
else if(strstri(compression, "BCM")) cs.compress_level = atoi(compression) | BCM;
|
||||
else cs.compress_level = isdigit(compression[0]) ? atoi(compression) : 6 /*| DEFL*/;
|
||||
}
|
||||
}
|
||||
|
||||
// if script was generated...
|
||||
if( script && script[0]) {
|
||||
// update outfile
|
||||
cs.finalfile = *OUTPUT;
|
||||
cs.outfile = *OUTPUT;
|
||||
|
||||
// amalgamate script
|
||||
array(char*) lines = strsplit(script, "\r\n");
|
||||
|
@ -290,15 +317,22 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
} else {
|
||||
// ... else bypass infile->outfile
|
||||
char** INFILE = map_find(symbols, "INFILE");
|
||||
cs.finalfile = *INFILE;
|
||||
cs.outfile = *INFILE;
|
||||
|
||||
// and return an empty script
|
||||
cs.script = "";
|
||||
}
|
||||
|
||||
map_clear(symbols);
|
||||
map_clear(groups);
|
||||
return cs;
|
||||
cs.outname = cs.outname ? cs.outname : (char*)infile;
|
||||
|
||||
ASSERT(mcs.num_passes < countof(mcs.cs));
|
||||
mcs.cs[mcs.num_passes++] = cs;
|
||||
|
||||
bool next_pass_required = mcs.num_passes < ext_num_groups;
|
||||
if( !next_pass_required ) break;
|
||||
}
|
||||
|
||||
return mcs;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -460,56 +494,53 @@ int cook(void *userdata) {
|
|||
*progress = ((i+1) == end ? 90 : (i * 90) / end); // (i+i>0) * 100.f / end;
|
||||
|
||||
// start cook
|
||||
const char *fname = uncooked[i]; //job->files[j];
|
||||
int inlen = file_size(fname);
|
||||
const char *infile = uncooked[i]; //job->files[j];
|
||||
int inlen = file_size(infile);
|
||||
|
||||
// generate a cooking script for this asset
|
||||
cook_script_t cs = cook_script(job->rules, fname, COOK_TMPFILE);
|
||||
cook_script_t mcs = cook_script(job->rules, infile, COOK_TMPFILE);
|
||||
// puts(cs.script);
|
||||
|
||||
for(int pass = 0; pass < mcs.num_passes; ++pass) {
|
||||
cook_subscript_t cs = mcs.cs[pass];
|
||||
|
||||
// log to batch file for forensic purposes, if explicitly requested
|
||||
static __thread bool logging = 0, *init = 0; if(!init) *(init = &logging) = !!flag("--cook-debug") || cook_debug;
|
||||
static __thread bool logging = 0; do_once logging = !!flag("--cook-debug") || cook_debug;
|
||||
if( logging ) {
|
||||
FILE *logfile = fopen(va("cook%d.cmd",job->threadid), "a+t");
|
||||
if( logfile ) { fprintf(logfile, "@rem %s\n%s\n", fname, cs.script); fclose(logfile); }
|
||||
// maybe log fprintf(logfile, "@rem %*.s\n", 4096, app_exec_output()); ?
|
||||
if( logfile ) { fprintf(logfile, "@rem %s\n%s\n", cs.outname, cs.script); fclose(logfile); }
|
||||
fprintf(stderr, "%s\n", cs.script);
|
||||
}
|
||||
|
||||
// invoke cooking script and recap status
|
||||
const char *rcout = app_exec(cs.script);
|
||||
int rc = atoi(rcout);
|
||||
int outlen = file_size(cs.finalfile);
|
||||
const char *rc_output = app_exec(cs.script);
|
||||
int rc = atoi(rc_output);
|
||||
int outlen = file_size(cs.outfile);
|
||||
int failed = cs.script[0] ? rc || !outlen : 0;
|
||||
|
||||
// print errors, or...
|
||||
if( failed ) {
|
||||
PRINTF("Import failed: %s while executing:\n%s\nReturned:\n%s\n", fname, cs.script, rcout);
|
||||
PRINTF("Import failed: %s while executing:\n%s\nReturned:\n%s\n", cs.outname, cs.script, rc_output);
|
||||
}
|
||||
// ...process only if included. may include optional compression.
|
||||
else if( cs.compress_level >= 0 ) {
|
||||
FILE *in = fopen(cs.finalfile, "rb");
|
||||
FILE *in = fopen(cs.outfile, "rb");
|
||||
|
||||
#if 0
|
||||
struct stat st; stat(fname, &st);
|
||||
#if 0
|
||||
struct stat st; stat(infile, &st);
|
||||
struct tm *timeinfo = localtime(&st.st_mtime);
|
||||
ASSERT(timeinfo);
|
||||
|
||||
// pretty (truncated) input (C:/prj/V4K/art/file.wav -> file.wav)
|
||||
static __thread int artlen = 0; if(!artlen) artlen = strlen(ART);
|
||||
const char *pretty = fname;
|
||||
if( !strncmp(pretty, ART, artlen) ) pretty += artlen;
|
||||
while(pretty[0] == '/') ++pretty;
|
||||
fname = pretty;
|
||||
//puts(fname);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
char *comment = va("%d", inlen);
|
||||
if( !zip_append_file/*_timeinfo*/(z, fname, comment, in, cs.compress_level/*, timeinfo*/) ) {
|
||||
PANIC("failed to add processed file into %s: %s", zipfile, fname);
|
||||
if( !zip_append_file/*_timeinfo*/(z, cs.outname, comment, in, cs.compress_level/*, timeinfo*/) ) {
|
||||
PANIC("failed to add processed file into %s: %s(%s)", zipfile, cs.outname, infile);
|
||||
}
|
||||
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
zip_close(z);
|
||||
|
|
|
@ -27,8 +27,8 @@ API const char * xml_string(char *key);
|
|||
API unsigned xml_count(char *key);
|
||||
API array(char) xml_blob(char *key);
|
||||
#define xml_string(...) xml_string(va(__VA_ARGS__)) // syntax sugar: string
|
||||
#define xml_int(...) atoi(xml_string(va(__VA_ARGS__))) // syntax sugar: int
|
||||
#define xml_float(...) atof(xml_string(va(__VA_ARGS__))) // syntax sugar: float
|
||||
#define xml_int(...) atoi(xml_string(__VA_ARGS__)) // syntax sugar: int
|
||||
#define xml_float(...) atof(xml_string(__VA_ARGS__)) // syntax sugar: float
|
||||
#define xml_blob(...) xml_blob(va(__VA_ARGS__)) // syntax sugar: base64 blob
|
||||
#define xml_count(...) xml_count(va(__VA_ARGS__)) // syntax sugar: count nodes
|
||||
API void xml_pop();
|
||||
|
|
151
engine/v4k.c
151
engine/v4k.c
|
@ -2942,31 +2942,42 @@ const char *COOK_INI = "tools/cook.ini";
|
|||
static unsigned ART_SKIP_ROOT; // number of chars to skip the base root in ART folder
|
||||
static unsigned ART_LEN; // dupe
|
||||
|
||||
typedef struct cook_script_t {
|
||||
char *infile; // free after use
|
||||
char *finalfile; // free after use. can be either infile or a totally different file
|
||||
typedef struct cook_subscript_t {
|
||||
char *infile;
|
||||
char *outfile; // can be either infile, or a totally different file
|
||||
char *script;
|
||||
char *outname;
|
||||
int compress_level;
|
||||
} cook_subscript_t;
|
||||
|
||||
typedef struct cook_script_t {
|
||||
cook_subscript_t cs[8];
|
||||
|
||||
int num_passes;
|
||||
} cook_script_t;
|
||||
|
||||
static
|
||||
cook_script_t cook_script(const char *rules, const char *infile, const char *outfile) {
|
||||
cook_script_t mcs = { 0 };
|
||||
|
||||
// pass loop: some asset rules may require multiple cook passes
|
||||
for( int pass = 0; pass < countof(mcs.cs); ++pass ) {
|
||||
// by default, assume:
|
||||
// - no script is going to be generated (empty script)
|
||||
// - if no script is going to be generated, output is in fact input file.
|
||||
// - no compression is going to be required.
|
||||
cook_script_t cs = { 0 };
|
||||
cook_subscript_t cs = { 0 };
|
||||
|
||||
// reuse script heap from last call if possible (optimization)
|
||||
static __thread char *script = 0;
|
||||
if(script) script[0] = 0;
|
||||
|
||||
// reuse parsing maps if possible (optimization)
|
||||
static __thread map(char*, char*) symbols = 0;
|
||||
static __thread map(char*, char*) groups = 0;
|
||||
|
||||
if(!symbols) map_init(symbols, less_str, hash_str);
|
||||
if(!groups) map_init(groups, less_str, hash_str);
|
||||
static __thread map(char*, char*) symbols = 0; if(!symbols) map_init_str(symbols);
|
||||
static __thread map(char*, char*) groups = 0; if(!groups) map_init_str(groups);
|
||||
static __thread set(char*) passes = 0; if(!passes) set_init_str(passes);
|
||||
map_clear(symbols);
|
||||
map_clear(groups);
|
||||
|
||||
map_find_or_add(symbols, "INFILE", STRDUP(infile));
|
||||
map_find_or_add(symbols, "INPUT", STRDUP(infile));
|
||||
|
@ -2976,6 +2987,9 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
map_find_or_add(symbols, "EDITOR", STRDUP(EDITOR));
|
||||
map_find_or_add(symbols, "PROGRESS", STRDUP(va("%03d", cook_progress())));
|
||||
|
||||
// clear pass counter
|
||||
set_clear(passes);
|
||||
|
||||
// start parsing. parsing is enabled by default
|
||||
int enabled = 1;
|
||||
array(char*)lines = strsplit(rules, "\r\n");
|
||||
|
@ -3010,11 +3024,11 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
if( eos ) *eos = 0;
|
||||
|
||||
// replace all symbols
|
||||
char* nl = STRDUP(line);
|
||||
char* nl = STRDUP(line); // @leak
|
||||
for each_map(symbols, char*, key, char*, val) {
|
||||
strrepl(&nl, key, val);
|
||||
}
|
||||
lines[i] = line = nl; // @fixme:leak
|
||||
lines[i] = line = nl;
|
||||
|
||||
static thread_mutex_t lock, *init = 0; if(!init) thread_mutex_init(init = &lock);
|
||||
thread_mutex_lock( &lock );
|
||||
|
@ -3028,9 +3042,9 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
enabled = 1;
|
||||
int is_cook = !!strstr(line, "[cook]");
|
||||
int is_compress = !!strstr(line, "[compress]");
|
||||
if( !is_cook && !is_compress ) {
|
||||
if( !is_cook && !is_compress ) { // if not a special section...
|
||||
// remove hint cook tag if present. that's informative only.
|
||||
if(strbegi(line, "[cook ") ) memcpy(line+1, " ", 4);
|
||||
if(strbegi(line, "[cook ") ) memcpy(line+1, " ", 4); // line += 6;
|
||||
|
||||
// start parsing expressions like `[media && !avi && mp3]`
|
||||
array(char*) tags = strsplit(line, " []&");
|
||||
|
@ -3039,8 +3053,9 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
char **INPUT = map_find(symbols, "INPUT");
|
||||
bool found_in_set = true;
|
||||
|
||||
for( int i = 0, end = array_count(tags); i < end; ++i) { char *tag = tags[i];
|
||||
for( int i = 0, end = array_count(tags); i < end; ++i) {
|
||||
bool negate = false;
|
||||
char *tag = tags[i];
|
||||
while(*tag == '!') negate ^= 1, ++tag;
|
||||
|
||||
// find tag in groups map
|
||||
|
@ -3050,7 +3065,7 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
char *list = *is_group;
|
||||
char *INPUT_EXT = file_ext(infile); INPUT_EXT = strrchr(INPUT_EXT, '.'); // .ext1.ext -> .ext
|
||||
char *ext = INPUT_EXT; ext += ext[0] == '.'; // dotless
|
||||
bool in_list = strbegi(list, ext) || strstri(list, va(",%s,",ext)) || strendi(list, va(",%s",ext));
|
||||
bool in_list = strbegi(list, ext) || strendi(list, va(",%s",ext)) || strstri(list, va(",%s,",ext));
|
||||
if( !in_list ^ negate ) { found_in_set = false; break; }
|
||||
} else {
|
||||
char *ext = va(".%s", tag);
|
||||
|
@ -3058,6 +3073,13 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
if( !found ^ negate ) { found_in_set = false; break; }
|
||||
}
|
||||
}
|
||||
if( found_in_set ) {
|
||||
// inc pass
|
||||
set_find_or_add(passes, STRDUP(*tags)); // @leak
|
||||
// check whether we keep searching
|
||||
int num_passes = set_count(passes);
|
||||
found_in_set = ( pass == (num_passes-1) );
|
||||
}
|
||||
//
|
||||
enabled = found_in_set ? 1 : 0;
|
||||
}
|
||||
|
@ -3098,20 +3120,26 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
int errorlevel = has_errorlevel ? atoi(has_errorlevel + 2) : 0;
|
||||
if( has_errorlevel ) memcpy(has_errorlevel, " ", 3);
|
||||
|
||||
// detect if newer extension is present, and thus update OUTPUT if needed
|
||||
// detect if newer extension or filename is present, and thus update OUTPUT if needed
|
||||
char *newer_extension = strstr(line, "->"); if(newer_extension) {
|
||||
*newer_extension = 0;
|
||||
newer_extension += 2 + strspn(newer_extension + 2, " ");
|
||||
|
||||
if( strchr(newer_extension, '.') ) {
|
||||
// newer filename
|
||||
cs.outname = stringf("%s@%s", cs.outname ? cs.outname : infile, newer_extension); // @leak
|
||||
newer_extension = NULL;
|
||||
} else {
|
||||
strcatf(&*OUTPUT, ".%s", newer_extension);
|
||||
}
|
||||
}
|
||||
|
||||
// replace all symbols
|
||||
char* nl = STRDUP(line);
|
||||
char* nl = STRDUP(line); // @leak
|
||||
for each_map(symbols, char*, key, char*, val) {
|
||||
strrepl(&nl, key, val);
|
||||
}
|
||||
lines[i] = line = nl; // @fixme:leak
|
||||
lines[i] = line = nl;
|
||||
|
||||
// convert slashes
|
||||
ifdef(win32,
|
||||
|
@ -3136,43 +3164,41 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
}
|
||||
}
|
||||
|
||||
// compression
|
||||
char* ext = file_ext(infile); ext = strrchr(ext, '.'); ext += ext[0] == '.'; // dotless INPUT_EXT
|
||||
|
||||
char** OUTPUT = map_find(symbols, "OUTPUT");
|
||||
int ext_num_groups = 0;
|
||||
|
||||
// compression
|
||||
if( 1 ) {
|
||||
char* ext = file_ext(infile); ext = strrchr(ext, '.'); ext += ext[0] == '.'; // dotless INPUT_EXT
|
||||
char* belongs_to = 0;
|
||||
for each_map(groups, char*, key, char*, val) {
|
||||
if( !isdigit(key[0]) ) {
|
||||
char *comma = va(",%s,", ext);
|
||||
if( strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
if( !strcmpi(val,ext) || strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
belongs_to = key;
|
||||
//goto break1; // each_map() macro is made of multiple for(;;)s. goto needed; you cant escape with single break.
|
||||
ext_num_groups++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break1:;
|
||||
char *compression = 0;
|
||||
for each_map(groups, char*, key, char*, val) {
|
||||
if( isdigit(key[0]) ) {
|
||||
char *comma = va(",%s,", ext);
|
||||
if( strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
if( !strcmpi(val,ext) || strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
compression = key;
|
||||
//goto break2; // each_map() macro is made of multiple for(;;)s. goto needed; you cant escape with single break.
|
||||
}
|
||||
comma = va(",%s,", belongs_to);
|
||||
if( strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
if( !strcmpi(val,ext) || strbegi(val, comma+1) || strstri(val, comma) || strendi(val, va(",%s", ext))) {
|
||||
compression = key;
|
||||
//goto break2; // each_map() macro is made of multiple for(;;)s. goto needed; you cant escape with single break.
|
||||
}
|
||||
}
|
||||
}
|
||||
break2:;
|
||||
|
||||
cs.compress_level = 0;
|
||||
if( compression ) {
|
||||
// last chance to optionally override the compressor at command-line level
|
||||
static const char *compressor_override, **init = 0;
|
||||
if( !init ) *(init = &compressor_override) = option("--cook-compressor", "");
|
||||
static const char *compressor_override;
|
||||
do_once compressor_override = option("--cook-compressor", "");
|
||||
if( compressor_override[0] ) compression = (char*)compressor_override;
|
||||
|
||||
/**/ if(strstri(compression, "PPP")) cs.compress_level = atoi(compression) | PPP;
|
||||
|
@ -3188,11 +3214,12 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
else if(strstri(compression, "BCM")) cs.compress_level = atoi(compression) | BCM;
|
||||
else cs.compress_level = isdigit(compression[0]) ? atoi(compression) : 6 /*| DEFL*/;
|
||||
}
|
||||
}
|
||||
|
||||
// if script was generated...
|
||||
if( script && script[0]) {
|
||||
// update outfile
|
||||
cs.finalfile = *OUTPUT;
|
||||
cs.outfile = *OUTPUT;
|
||||
|
||||
// amalgamate script
|
||||
array(char*) lines = strsplit(script, "\r\n");
|
||||
|
@ -3215,15 +3242,22 @@ cook_script_t cook_script(const char *rules, const char *infile, const char *out
|
|||
} else {
|
||||
// ... else bypass infile->outfile
|
||||
char** INFILE = map_find(symbols, "INFILE");
|
||||
cs.finalfile = *INFILE;
|
||||
cs.outfile = *INFILE;
|
||||
|
||||
// and return an empty script
|
||||
cs.script = "";
|
||||
}
|
||||
|
||||
map_clear(symbols);
|
||||
map_clear(groups);
|
||||
return cs;
|
||||
cs.outname = cs.outname ? cs.outname : (char*)infile;
|
||||
|
||||
ASSERT(mcs.num_passes < countof(mcs.cs));
|
||||
mcs.cs[mcs.num_passes++] = cs;
|
||||
|
||||
bool next_pass_required = mcs.num_passes < ext_num_groups;
|
||||
if( !next_pass_required ) break;
|
||||
}
|
||||
|
||||
return mcs;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -3385,56 +3419,53 @@ int cook(void *userdata) {
|
|||
*progress = ((i+1) == end ? 90 : (i * 90) / end); // (i+i>0) * 100.f / end;
|
||||
|
||||
// start cook
|
||||
const char *fname = uncooked[i]; //job->files[j];
|
||||
int inlen = file_size(fname);
|
||||
const char *infile = uncooked[i]; //job->files[j];
|
||||
int inlen = file_size(infile);
|
||||
|
||||
// generate a cooking script for this asset
|
||||
cook_script_t cs = cook_script(job->rules, fname, COOK_TMPFILE);
|
||||
cook_script_t mcs = cook_script(job->rules, infile, COOK_TMPFILE);
|
||||
// puts(cs.script);
|
||||
|
||||
for(int pass = 0; pass < mcs.num_passes; ++pass) {
|
||||
cook_subscript_t cs = mcs.cs[pass];
|
||||
|
||||
// log to batch file for forensic purposes, if explicitly requested
|
||||
static __thread bool logging = 0, *init = 0; if(!init) *(init = &logging) = !!flag("--cook-debug") || cook_debug;
|
||||
static __thread bool logging = 0; do_once logging = !!flag("--cook-debug") || cook_debug;
|
||||
if( logging ) {
|
||||
FILE *logfile = fopen(va("cook%d.cmd",job->threadid), "a+t");
|
||||
if( logfile ) { fprintf(logfile, "@rem %s\n%s\n", fname, cs.script); fclose(logfile); }
|
||||
// maybe log fprintf(logfile, "@rem %*.s\n", 4096, app_exec_output()); ?
|
||||
if( logfile ) { fprintf(logfile, "@rem %s\n%s\n", cs.outname, cs.script); fclose(logfile); }
|
||||
fprintf(stderr, "%s\n", cs.script);
|
||||
}
|
||||
|
||||
// invoke cooking script and recap status
|
||||
const char *rcout = app_exec(cs.script);
|
||||
int rc = atoi(rcout);
|
||||
int outlen = file_size(cs.finalfile);
|
||||
const char *rc_output = app_exec(cs.script);
|
||||
int rc = atoi(rc_output);
|
||||
int outlen = file_size(cs.outfile);
|
||||
int failed = cs.script[0] ? rc || !outlen : 0;
|
||||
|
||||
// print errors, or...
|
||||
if( failed ) {
|
||||
PRINTF("Import failed: %s while executing:\n%s\nReturned:\n%s\n", fname, cs.script, rcout);
|
||||
PRINTF("Import failed: %s while executing:\n%s\nReturned:\n%s\n", cs.outname, cs.script, rc_output);
|
||||
}
|
||||
// ...process only if included. may include optional compression.
|
||||
else if( cs.compress_level >= 0 ) {
|
||||
FILE *in = fopen(cs.finalfile, "rb");
|
||||
FILE *in = fopen(cs.outfile, "rb");
|
||||
|
||||
#if 0
|
||||
struct stat st; stat(fname, &st);
|
||||
#if 0
|
||||
struct stat st; stat(infile, &st);
|
||||
struct tm *timeinfo = localtime(&st.st_mtime);
|
||||
ASSERT(timeinfo);
|
||||
|
||||
// pretty (truncated) input (C:/prj/V4K/art/file.wav -> file.wav)
|
||||
static __thread int artlen = 0; if(!artlen) artlen = strlen(ART);
|
||||
const char *pretty = fname;
|
||||
if( !strncmp(pretty, ART, artlen) ) pretty += artlen;
|
||||
while(pretty[0] == '/') ++pretty;
|
||||
fname = pretty;
|
||||
//puts(fname);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
char *comment = va("%d", inlen);
|
||||
if( !zip_append_file/*_timeinfo*/(z, fname, comment, in, cs.compress_level/*, timeinfo*/) ) {
|
||||
PANIC("failed to add processed file into %s: %s", zipfile, fname);
|
||||
if( !zip_append_file/*_timeinfo*/(z, cs.outname, comment, in, cs.compress_level/*, timeinfo*/) ) {
|
||||
PANIC("failed to add processed file into %s: %s(%s)", zipfile, cs.outname, infile);
|
||||
}
|
||||
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
zip_close(z);
|
||||
|
|
|
@ -1501,8 +1501,8 @@ API const char * xml_string(char *key);
|
|||
API unsigned xml_count(char *key);
|
||||
API array(char) xml_blob(char *key);
|
||||
#define xml_string(...) xml_string(va(__VA_ARGS__)) // syntax sugar: string
|
||||
#define xml_int(...) atoi(xml_string(va(__VA_ARGS__))) // syntax sugar: int
|
||||
#define xml_float(...) atof(xml_string(va(__VA_ARGS__))) // syntax sugar: float
|
||||
#define xml_int(...) atoi(xml_string(__VA_ARGS__)) // syntax sugar: int
|
||||
#define xml_float(...) atof(xml_string(__VA_ARGS__)) // syntax sugar: float
|
||||
#define xml_blob(...) xml_blob(va(__VA_ARGS__)) // syntax sugar: base64 blob
|
||||
#define xml_count(...) xml_count(va(__VA_ARGS__)) // syntax sugar: count nodes
|
||||
API void xml_pop();
|
||||
|
|
|
@ -596,7 +596,7 @@ details > summary::-webkit-details-marker {
|
|||
|Version: | 2023.7 |
|
||||
|:--------------|:------------|
|
||||
|Branch: | main |
|
||||
|Commit: | 62 |
|
||||
|Commit: | 63 |
|
||||
<!--| Documentation last modified | { {LAST_MODIFIED} } |-->
|
||||
|
||||
# [V·4·K 2023.7 ](https://dev.v4.games/zaklaus/v4k)
|
||||
|
@ -8667,7 +8667,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
## shaders
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_0_0_shadowmap_lit;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8676,7 +8676,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_0_0_shadowmap_unlit;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8685,7 +8685,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_24_4_sprite;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8694,7 +8694,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_2_4_preamble;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8703,7 +8703,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_2_4_texel_inv_gamma;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8712,7 +8712,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_2_4_texel_ycbr_gamma_saturation;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8721,7 +8721,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_32_4_model;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8730,7 +8730,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_32_4_model_basic;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8739,7 +8739,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_3_4_skybox;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8748,7 +8748,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_3_4_skybox_rayleigh;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8757,7 +8757,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const fs_main_shadertoy;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8766,7 +8766,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const vs_0_2_fullscreen_quad_A;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8775,7 +8775,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const vs_0_2_fullscreen_quad_B;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8784,7 +8784,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const vs_0_2_fullscreen_quad_B_flipped;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8793,7 +8793,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const vs_323444143_16_332_model;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8802,7 +8802,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const vs_324_24_sprite;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8811,7 +8811,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const vs_332_32;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
@ -8820,7 +8820,7 @@ Other documentation examples: [dll](#dll), [strsplit](#strsplit), [strjoin](#str
|
|||
|
||||
</details>
|
||||
|
||||
<a name=""></a>
|
||||
<a name="ned"></a>
|
||||
<details><summary><code lang=C> extern const char* const vs_3_3_skybox;</code></summary>
|
||||
|
||||
Under construction. Yet to be documented.
|
||||
|
|
BIN
tools/cook.exe
BIN
tools/cook.exe
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
; this is where you specify and configure the FWK pipeline.
|
||||
; this is where you specify and configure the V4K pipeline.
|
||||
; tweak the pipeline and add new importers just by editing this file.
|
||||
; there is no flow control in this script file: lines are parsed and evaluated, from top to bottom.
|
||||
|
||||
|
@ -6,11 +6,11 @@
|
|||
; let's create a symbol. symbols are uppercase words always.
|
||||
; syntax: symbols are defined in KEY=value form, as seen below.
|
||||
|
||||
TOOLS=./ ; folder where our pipeline tools are located
|
||||
ART=../demos/art/,../engine/art/ ; comma-separated folder(s) that store all our asset files
|
||||
TOOLS=./ ; where our pipeline tools are located
|
||||
|
||||
; lines starting with @windows, @linux or @osx will be processed only where OS matches.
|
||||
; we are defining here some symbols differently on each platform.
|
||||
; we are defining here some symbols differently for each platform.
|
||||
; syntax: lines starting with @keyword. valid keywords are win/dows, lin/ux, and osx.
|
||||
|
||||
@linux NUL=/dev/null
|
||||
|
@ -23,7 +23,7 @@ TOOLS=./ ; where our pipeline tools are located
|
|||
|
||||
; you can invoke shell commands directly with `command` at anytime.
|
||||
; also, once a symbol is found, it is replaced by its value always.
|
||||
; PROGRESS (percent), INPUT (input filename), OUTPUT (output filename) and PRETTY (clean input filename) are some predefined symbols.
|
||||
; some predefined symbols: INPUT (input filename), OUTPUT (output filename), PRETTY (clean input filename), PROGRESS (cook progress).
|
||||
|
||||
@windows `echo Cooking PROGRESS% PRETTY...`
|
||||
@linux `echo "Cooking PROGRESS% PRETTY..."`
|
||||
|
@ -35,16 +35,16 @@ TOOLS=./ ; where our pipeline tools are located
|
|||
; syntax: group=ext1,ext2[...]
|
||||
|
||||
[cook]
|
||||
icons=ico
|
||||
image=jpg,png,bmp,psd,pic,pnm,hdr
|
||||
icon=ico
|
||||
image=jpg,jpeg,png,bmp,psd,pic,pnm,hdr
|
||||
texture=pvr,ktx,ktx2,dds,astc,basis,tga
|
||||
anim=fbx
|
||||
model=iqm,iqe,gltf,gltf2,glb,fbx,obj,dae,blend,md3,md5,ms3d,smd,x,3ds,bvh,dxf,lwo
|
||||
anims=anim
|
||||
audio=wav,flac,ogg,mp1,mp3,mid,sfxr ; ,mod,xm
|
||||
audio-modules=mod,xm,s3m,it
|
||||
audio-module=mod,xm,s3m,it
|
||||
audio-furnace=fur
|
||||
font=ttf,ttc,otf
|
||||
text=json,xml,csv,ini,cfg,doc,txt,md,c,h,lua,inl,cpp,hpp,htm,html
|
||||
text=json,xml,csv,ini,cfg,doc,txt,md,c,h,inl,cpp,hpp,htm,html
|
||||
shader=hlsl,fx,dxil,dxbc,glsl,vert,frag,geom,tese,tesc,comp,vs,fs,gs,ts,cs,spirv,spv,slang
|
||||
script=lua,tl
|
||||
video=mp4,ogv,avi,mkv,wmv,mpg,mpeg
|
||||
|
@ -58,7 +58,7 @@ tiled=tmx,tsx
|
|||
; hint: the ->ogg and ->wav parts below do signal the pipeline that the commands we are about
|
||||
; to execute are performing a data conversion (from flac to ogg for example).
|
||||
|
||||
[cook audio-modules]
|
||||
[cook audio-module]
|
||||
TOOLS/mod2wav.EXE INPUT OUTPUT -> wav
|
||||
TOOLS/ffmpeg.EXE -hide_banner -nostdin -loglevel fatal -y -i INPUT -f ogg -b:a 192k OUTPUT -> ogg ; -stats
|
||||
|
||||
|
@ -164,16 +164,12 @@ TOOLS/cuttlefish.EXE -q -m -i INPUT -o OUTPUT -f BC1_RGBA -> ktx
|
|||
|
||||
; ------------------------------------------------------------------------------
|
||||
; finally, let's cook all models. the logic here is:
|
||||
; 1. export animation list from models using ass2iqe -L
|
||||
; 2. cook all models into iqe (ass2iqe), then into iqm (iqe2iqm): any -> iqe -> iqm
|
||||
; 3. unless input is iqe. these models will run iqe2iqm only (no ass2iqe): iqe -> iqm.
|
||||
; 4. unless input is iqm. these models will not run any conversion at all: iqm.
|
||||
; 5. also, dae models need to flip their UVs coordinates (see -U flag below).
|
||||
; 1. cook all models into iqe (ass2iqe), then into iqm (iqe2iqm): any -> iqe -> iqm
|
||||
; 2. unless input is iqe. these models will run iqe2iqm only (no ass2iqe): iqe -> iqm.
|
||||
; 3. unless input is iqm. these models will not run any conversion at all: iqm.
|
||||
; 4. also, dae models need to flip their UVs coordinates (see -U flag below).
|
||||
|
||||
[cook anims] ; process all models to extract animlist
|
||||
TOOLS/ass2iqe.EXE -L -o OUTPUT INPUT 2> NUL
|
||||
|
||||
[cook model && dae &&] ; pass dae, reject iqm,iqe or any other model
|
||||
[cook model && dae] ; pass dae, reject iqm,iqe or any other model
|
||||
FLAGS=
|
||||
TOOLS/ass2iqe.EXE FLAGS -o OUTPUT INPUT -U 2> NUL -> iqe
|
||||
|
||||
|
@ -184,6 +180,10 @@ TOOLS/ass2iqe.EXE FLAGS -o OUTPUT INPUT 2> NUL -> iqe
|
|||
[cook model && !iqm]
|
||||
TOOLS/iqe2iqm.EXE OUTPUT INPUT > NUL -> iqm
|
||||
|
||||
[cook anim]
|
||||
FLAGS=
|
||||
TOOLS/ass2iqe.EXE FLAGS -L -o OUTPUT INPUT 2> NUL -> animlist.txt
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
; cook localization files
|
||||
|
||||
|
@ -204,5 +204,5 @@ TOOLS/iqe2iqm.EXE OUTPUT INPUT > NUL -> iqm
|
|||
; hint: use plain `0` to exclude those files we would like to directly stream within the final zipfile (flac,mp3,adpcm wav,...)
|
||||
|
||||
[compress]
|
||||
0|ULZ=texture,image,model,audio,font,text,shader,script,animlist
|
||||
0|ULZ=texture,image,model,audio,font,text,shader,script
|
||||
0=video,flac,ogg,wav,mp1,mp3,jpg,png
|
Loading…
Reference in New Issue