mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-30 07:31:13 +00:00
4d25c073ec
fix crash from qwplayers with invalid modelindexes rework allow_skybox a little. now applies immediately. try to fix the appears-outside-of-map bug, again. dir *.wav now shows a little extra info on mouse-over. try loading music file extensions that we expect to be able to play via ffmpeg, not just the ones that are directly supported. rework the hidden fps_presets, show them with tab completion. fix a possible crash with r_temporalscenecache fix lightmap updates on submodels not happening properly with the scenecache. fix the serious memory leak with scenecache. add r_glsl_pbr cvar to force use of pbr pathways in our glsl. fix bug in alsa output not supporting float output properly. preliminary work to have the mixer use floating point mixing. disabled for now. try to update sys_register_file_associations on linux, still needs work though. try to work around nquake's config quirks, so config files don't get overwritten. repackage quake's conchars in order to add padding. this should avoid extra junk on the outside of glyphs. give fteqcc(commandline version) some extra package extration/creation support. our paks should be more end-user-friendly, and our spanned pk3s are awesome. write rune state to legacy saved games, so we don't ever have the missing-runes bug ever again... git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5780 fc73d0e0-1445-4013-8a0c-d673dee63da5
329 lines
7.7 KiB
C
329 lines
7.7 KiB
C
#include "qcc.h"
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
|
|
#if defined(__linux__) || defined(__unix__)
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
/*
|
|
==============
|
|
LoadFile
|
|
==============
|
|
*/
|
|
static void *QCC_ReadFile(const char *fname, unsigned char *(*buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *out_size, pbool issourcefile)
|
|
//unsigned char *PDECL QCC_ReadFile (const char *fname, void *buffer, int len, size_t *sz)
|
|
{
|
|
size_t len;
|
|
FILE *f;
|
|
char *buffer;
|
|
|
|
f = fopen(fname, "rb");
|
|
if (!f)
|
|
{
|
|
if (out_size)
|
|
*out_size = 0;
|
|
return NULL;
|
|
}
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
len = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
if (buf_get)
|
|
buffer = buf_get(buf_ctx, len+1);
|
|
else
|
|
buffer = malloc(len+1);
|
|
((char*)buffer)[len] = 0;
|
|
if (len != fread(buffer, 1, len, f))
|
|
{
|
|
if (!buf_get)
|
|
free(buffer);
|
|
buffer = NULL;
|
|
}
|
|
fclose(f);
|
|
|
|
if (out_size)
|
|
*out_size = len;
|
|
return buffer;
|
|
}
|
|
static int PDECL QCC_FileSize (const char *fname)
|
|
{
|
|
long length;
|
|
FILE *f;
|
|
f = fopen(fname, "rb");
|
|
if (!f)
|
|
return -1;
|
|
fseek(f, 0, SEEK_END);
|
|
length = ftell(f);
|
|
fclose(f);
|
|
|
|
return length;
|
|
}
|
|
|
|
static pbool PDECL QCC_WriteFile (const char *name, void *data, int len)
|
|
{
|
|
long length;
|
|
FILE *f;
|
|
f = fopen(name, "wb");
|
|
if (!f)
|
|
return false;
|
|
length = fwrite(data, 1, len, f);
|
|
fclose(f);
|
|
|
|
if (length != len)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
#undef printf
|
|
#undef Sys_Error
|
|
|
|
static void PDECL Sys_Error(const char *text, ...)
|
|
{
|
|
va_list argptr;
|
|
static char msg[2048];
|
|
|
|
va_start (argptr,text);
|
|
QC_vsnprintf (msg,sizeof(msg)-1, text,argptr);
|
|
va_end (argptr);
|
|
|
|
QCC_Error(ERR_INTERNAL, "%s", msg);
|
|
}
|
|
|
|
|
|
static FILE *logfile;
|
|
static int logprintf(const char *format, ...)
|
|
{
|
|
va_list argptr;
|
|
static char string[1024];
|
|
|
|
va_start (argptr, format);
|
|
#ifdef _WIN32
|
|
_vsnprintf (string,sizeof(string)-1, format,argptr);
|
|
#else
|
|
vsnprintf (string,sizeof(string), format,argptr);
|
|
#endif
|
|
va_end (argptr);
|
|
|
|
printf("%s", string);
|
|
// fputs(string, stderr);
|
|
if (logfile)
|
|
fputs(string, logfile);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static size_t totalsize, filecount;
|
|
static void QCC_FileList(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize)
|
|
{
|
|
totalsize += plainsize;
|
|
filecount += 1;
|
|
if (!method && compsize==plainsize)
|
|
externs->Printf("%8u %s\n", (unsigned)plainsize, name);
|
|
else
|
|
externs->Printf("%8u %3u%% %s\n", (unsigned)plainsize, plainsize?(unsigned)((100*compsize)/plainsize):100u, name);
|
|
}
|
|
#include <limits.h>
|
|
#ifdef __unix__
|
|
#include <sys/stat.h>
|
|
void QCC_Mkdir(const char *path)
|
|
{
|
|
char buf[MAX_OSPATH], *sl;
|
|
if (!strchr(path, '/'))
|
|
return; //no need to create anything
|
|
memcpy(buf, path, MAX_OSPATH);
|
|
while((sl=strrchr(buf, '/')))
|
|
{
|
|
*sl = 0;
|
|
mkdir(buf, 0777);
|
|
}
|
|
}
|
|
#else
|
|
void QCC_Mkdir(const char *path)
|
|
{
|
|
//unsupported.
|
|
}
|
|
#endif
|
|
static const char *extractonly;
|
|
static pbool extractonlyfound;
|
|
static void QCC_FileExtract(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize)
|
|
{
|
|
if (extractonly)
|
|
{
|
|
const char *sl = strrchr(extractonly, '/');
|
|
if (sl && !sl[1])
|
|
{ //trailing / - extract the entire dir.
|
|
if (!strcmp(name, extractonly))
|
|
return; //ignore the dir itself...
|
|
if (strncmp(name, extractonly, strlen(extractonly)))
|
|
return;
|
|
}
|
|
else
|
|
if (strcmp(name, extractonly))
|
|
return; //ignore it if its not the one we're going for.
|
|
}
|
|
extractonlyfound = true;
|
|
externs->Printf("Extracting %s...", name);
|
|
if (plainsize <= INT_MAX)
|
|
{
|
|
void *buffer = malloc(plainsize);
|
|
if (buffer && QC_decode(progfuncs, compsize, plainsize, method, compdata, buffer))
|
|
{
|
|
QCC_Mkdir(name);
|
|
if (!QCC_WriteFile(name, buffer, plainsize))
|
|
externs->Printf(" write failure\n");
|
|
else
|
|
externs->Printf(" done\n");
|
|
}
|
|
else
|
|
externs->Printf(" read failure\n");
|
|
|
|
free(buffer);
|
|
}
|
|
else
|
|
externs->Printf(" too large\n");
|
|
}
|
|
|
|
static void QCC_PR_PackagerMessage(void *userctx, const char *message, ...)
|
|
{
|
|
va_list argptr;
|
|
char string[1024];
|
|
|
|
va_start (argptr,message);
|
|
QC_vsnprintf (string,sizeof(string)-1,message,argptr);
|
|
va_end (argptr);
|
|
|
|
externs->Printf ("%s", string);
|
|
}
|
|
|
|
int main (int argc, const char **argv)
|
|
{
|
|
unsigned int i;
|
|
pbool sucess;
|
|
#if 0//def _WIN32
|
|
pbool writelog = true; //spew log files on windows. windows often closes the window as soon as the program ends making its output otherwise unreadable.
|
|
#else
|
|
pbool writelog = false; //other systems are sane.
|
|
#endif
|
|
int colours = 2; //auto
|
|
progexterns_t ext;
|
|
progfuncs_t funcs;
|
|
progfuncs = &funcs;
|
|
memset(&funcs, 0, sizeof(funcs));
|
|
funcs.funcs.parms = &ext;
|
|
memset(&ext, 0, sizeof(progexterns_t));
|
|
funcs.funcs.parms->ReadFile = QCC_ReadFile;
|
|
funcs.funcs.parms->FileSize = QCC_FileSize;
|
|
funcs.funcs.parms->WriteFile = QCC_WriteFile;
|
|
funcs.funcs.parms->Printf = logprintf;
|
|
funcs.funcs.parms->Sys_Error = Sys_Error;
|
|
|
|
if ((argc == 3 && !strcmp(argv[1], "-l")) || (argc >= 3 && !strcmp(argv[1], "-x")))
|
|
{
|
|
size_t blobsize;
|
|
void *blob = QCC_ReadFile(argv[2], NULL, NULL, &blobsize, false);
|
|
if (!blob)
|
|
{
|
|
logprintf("Unable to read %s\n", argv[2]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (argc > 3)
|
|
{
|
|
for (i = 3; i < argc; i++)
|
|
{
|
|
extractonly = argv[i];
|
|
extractonlyfound = false;
|
|
QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileExtract);
|
|
if (!extractonlyfound)
|
|
externs->Printf("Unable to find file %s\n", extractonly);
|
|
}
|
|
extractonly = NULL;
|
|
}
|
|
else if (argv[1][1] == 'x')
|
|
QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileExtract);
|
|
else
|
|
{
|
|
QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileList);
|
|
externs->Printf("Total size %u bytes, %u files\n", (unsigned)totalsize, (unsigned)filecount);
|
|
}
|
|
free(blob);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
if (argc == 3 && (!strncmp(argv[1], "-z", 2) || !strcmp(argv[1], "-0") || !strcmp(argv[1], "-9")))
|
|
{ //exe -0 foo.pk3dir
|
|
enum pkgtype_e t;
|
|
if (argv[1][1] == '9')
|
|
t = PACKAGER_PK3;
|
|
else if (argv[1][1] == '0')
|
|
t = PACKAGER_PAK; //not really any difference but oh well
|
|
else
|
|
t = PACKAGER_PK3_SPANNED;
|
|
|
|
if (Packager_CompressDir(argv[2], t, QCC_PR_PackagerMessage, NULL))
|
|
return EXIT_SUCCESS;
|
|
else
|
|
return EXIT_FAILURE;
|
|
}
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
if (!argv[i])
|
|
continue;
|
|
if (!strcmp(argv[i], "-log"))
|
|
writelog = true;
|
|
else if (!strcmp(argv[i], "-nolog"))
|
|
writelog = false;
|
|
|
|
//arg consistency with ls
|
|
else if (!strcmp(argv[i], "--color=always") || !strcmp(argv[i], "--color"))
|
|
colours = 1;
|
|
else if (!strcmp(argv[i], "--color=never"))
|
|
colours = 0;
|
|
else if (!strcmp(argv[i], "--color=auto"))
|
|
colours = 2;
|
|
}
|
|
#if defined(__linux__) || defined(__unix__)
|
|
if (colours == 2)
|
|
colours = isatty(STDOUT_FILENO);
|
|
if (colours)
|
|
{ //only use colours if its a tty, and not if we're redirected.
|
|
col_none = "\e[0;m"; //reset to white
|
|
col_error = "\e[0;31m"; //red
|
|
col_symbol = "\e[0;32m"; //green
|
|
col_warning = "\e[0;33m"; //yellow
|
|
//col_ = "\e[0;34m"; //blue
|
|
col_name = "\e[0;35m"; //magenta
|
|
col_type = "\e[0;36m"; //cyan
|
|
col_location = "\e[0;1;37m"; //bright white
|
|
}
|
|
#else
|
|
(void)colours;
|
|
#endif
|
|
|
|
logfile = writelog?fopen("fteqcc.log", "wt"):false;
|
|
|
|
if (logfile)
|
|
{
|
|
fputs("Args:", logfile);
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
if (!argv[i])
|
|
continue;
|
|
if (strchr(argv[i], ' '))
|
|
fprintf(logfile, " \"%s\"", argv[i]);
|
|
else
|
|
fprintf(logfile, " %s", argv[i]);
|
|
}
|
|
fprintf(logfile, "\n");
|
|
}
|
|
sucess = CompileParams(&funcs, NULL, argc, argv);
|
|
qccClearHunk();
|
|
if (logfile)
|
|
fclose(logfile);
|
|
|
|
#ifdef _WIN32
|
|
// fgetc(stdin); //wait for keypress
|
|
#endif
|
|
return sucess?EXIT_SUCCESS:EXIT_FAILURE;
|
|
}
|