Preliminary CoD formats support.
This commit is contained in:
parent
8dadfb4878
commit
1a446879d8
11 changed files with 3411 additions and 45 deletions
|
@ -937,22 +937,39 @@ IF(FTE_PLUG_QUAKE3)
|
||||||
#define the modules and make sure they're linked (one generic, one for server-only builds.
|
#define the modules and make sure they're linked (one generic, one for server-only builds.
|
||||||
ADD_LIBRARY(quake3 STATIC ${FTE_Q3_FILES})
|
ADD_LIBRARY(quake3 STATIC ${FTE_Q3_FILES})
|
||||||
SET_TARGET_PROPERTIES(quake3 PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON};BOTLIB;BOTLIB_STATIC;FTEPLUGIN;STATIC_Q3")
|
SET_TARGET_PROPERTIES(quake3 PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON};BOTLIB;BOTLIB_STATIC;FTEPLUGIN;STATIC_Q3")
|
||||||
TARGET_LINK_LIBRARIES(quake3 m)
|
TARGET_LINK_LIBRARIES(quake3 ${SYS_LIBS})
|
||||||
|
|
||||||
#ADD_LIBRARY(q3sv STATIC EXCLUDE_FROM_ALL ${FTE_Q3_FILES})
|
#ADD_LIBRARY(q3sv STATIC EXCLUDE_FROM_ALL ${FTE_Q3_FILES})
|
||||||
#SET_TARGET_PROPERTIES(q3sv PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON};BOTLIB;BOTLIB_STATIC;SERVERONLY")
|
#SET_TARGET_PROPERTIES(q3sv PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON};BOTLIB;BOTLIB_STATIC;SERVERONLY")
|
||||||
#SET_TARGET_PROPERTIES(q3sv PROPERTIES LINK_FLAGS "-Wl,--no-undefined")
|
#SET_TARGET_PROPERTIES(q3sv PROPERTIES LINK_FLAGS "-Wl,--no-undefined")
|
||||||
#TARGET_LINK_LIBRARIES(q3sv m)
|
#TARGET_LINK_LIBRARIES(q3sv ${SYS_LIBS})
|
||||||
#SET(FTESV_LIBS ${FTESV_LIBS} q3sv)
|
#SET(FTESV_LIBS ${FTESV_LIBS} q3sv)
|
||||||
ELSE()
|
ELSE()
|
||||||
#define the modules and make sure they're linked (one generic, one for server-only builds.
|
#define the modules and make sure they're linked (one generic, one for server-only builds.
|
||||||
ADD_LIBRARY(plug_quake3 MODULE ${FTE_Q3_FILES} plugins/plugin.c)
|
ADD_LIBRARY(plug_quake3 MODULE ${FTE_Q3_FILES} plugins/plugin.c)
|
||||||
SET_TARGET_PROPERTIES(plug_quake3 PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON};BOTLIB;BOTLIB_STATIC;FTEPLUGIN")
|
SET_TARGET_PROPERTIES(plug_quake3 PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON};BOTLIB;BOTLIB_STATIC;FTEPLUGIN")
|
||||||
TARGET_LINK_LIBRARIES(plug_quake3 m)
|
TARGET_LINK_LIBRARIES(plug_quake3 ${SYS_LIBS})
|
||||||
EMBED_PLUGIN_META(quake3 "Quake3 Compat" "Provides compatability with Quake3's gamecode.")
|
EMBED_PLUGIN_META(quake3 "Quake3 Compat" "Provides compatability with Quake3's gamecode.")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
#still a wip, so disabled by default
|
||||||
|
SET(FTE_PLUG_COD true CACHE BOOL "Compile Call of Duty plugin.")
|
||||||
|
IF(FTE_PLUG_COD)
|
||||||
|
ADD_LIBRARY(plug_cod MODULE
|
||||||
|
plugins/cod/codmod.c
|
||||||
|
plugins/cod/codbsp.c
|
||||||
|
plugins/cod/codmat.c
|
||||||
|
plugins/cod/codiwi.c
|
||||||
|
#plugins/cod/codff.c
|
||||||
|
plugins/plugin.c)
|
||||||
|
SET_TARGET_PROPERTIES(plug_cod PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON};FTEPLUGIN")
|
||||||
|
TARGET_LINK_LIBRARIES(plug_cod ${SYS_LIBS}
|
||||||
|
#${ZLIB_LIBRARIES}
|
||||||
|
)
|
||||||
|
EMBED_PLUGIN_META(cod "CoD Formats" "Provides compatability with Call Of Duty's file formats.")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
FILE(STRINGS "${FTE_BUILD_CONFIG}" BULLET_INTERNAL REGEX "^#define[\t ]+USE_INTERNAL_BULLET")
|
FILE(STRINGS "${FTE_BUILD_CONFIG}" BULLET_INTERNAL REGEX "^#define[\t ]+USE_INTERNAL_BULLET")
|
||||||
IF(BULLET_INTERNAL)
|
IF(BULLET_INTERNAL)
|
||||||
#Built-in bullet physics plugin...
|
#Built-in bullet physics plugin...
|
||||||
|
|
|
@ -4423,7 +4423,8 @@ static int QDECL CompleteModelViewerList (const char *name, qofs_t flags, time_t
|
||||||
|| !strcmp(ext, ".psk") || !strcmp(ext, ".md5mesh") || !strcmp(ext, ".md5anim")
|
|| !strcmp(ext, ".psk") || !strcmp(ext, ".md5mesh") || !strcmp(ext, ".md5anim")
|
||||||
|| !strcmp(ext, ".bsp") || !strcmp(ext, ".map") || !strcmp(ext, ".hmp")
|
|| !strcmp(ext, ".bsp") || !strcmp(ext, ".map") || !strcmp(ext, ".hmp")
|
||||||
|| !strcmp(ext, ".spr") || !strcmp(ext, ".sp2") || !strcmp(ext, ".spr32")
|
|| !strcmp(ext, ".spr") || !strcmp(ext, ".sp2") || !strcmp(ext, ".spr32")
|
||||||
|| !strcmp(ext, ".gltf") || !strcmp(ext, ".glb") || !strcmp(ext, ".ase") || !strcmp(ext, ".lwo") || !strcmp(ext, ".obj"))
|
|| !strcmp(ext, ".gltf") || !strcmp(ext, ".glb") || !strcmp(ext, ".ase") || !strcmp(ext, ".lwo") || !strcmp(ext, ".obj")
|
||||||
|
|| !strncmp(name, "xmodel/", 7) || !strncmp(name, "xanim/", 6)) //urgh!
|
||||||
{
|
{
|
||||||
ctx->cb(name, NULL, NULL, ctx);
|
ctx->cb(name, NULL, NULL, ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,6 +191,10 @@ static const gamemode_info_t gamemode_info[] = {
|
||||||
|
|
||||||
// {"-jk2", "jk2", "FTE-JK2", {"base/assets0.pk3"}, NULL, {"base", "*ftejk2"}, "Jedi Knight II: Jedi Outcast"},
|
// {"-jk2", "jk2", "FTE-JK2", {"base/assets0.pk3"}, NULL, {"base", "*ftejk2"}, "Jedi Knight II: Jedi Outcast"},
|
||||||
// {"-warsow", "warsow", "FTE-Warsow", {"basewsw/pak0.pk3"}, NULL, {"basewsw", "*ftewsw"}, "Warsow"},
|
// {"-warsow", "warsow", "FTE-Warsow", {"basewsw/pak0.pk3"}, NULL, {"basewsw", "*ftewsw"}, "Warsow"},
|
||||||
|
|
||||||
|
{"-cod4", NULL, "FTE-CoD4", {"cod4.ico"}, NULL, {"main", "*ftecod"}, "Call of Duty 4", NULL, "fteplug_cod"},
|
||||||
|
{"-cod2", NULL, "FTE-CoD2", {"main/iw_00.iwd"}, NULL, {"main", "*ftecod"}, "Call of Duty 2", NULL, "fteplug_cod"},
|
||||||
|
{"-cod", NULL, "FTE-CoD", {"Main/pak0.pk3"}, NULL, {"Main", "*ftecod"}, "Call of Duty", NULL, "fteplug_cod"},
|
||||||
#endif
|
#endif
|
||||||
#if !defined(QUAKETC) && !defined(MINIMAL)
|
#if !defined(QUAKETC) && !defined(MINIMAL)
|
||||||
// {"-doom", "doom", "FTE-Doom", {"doom.wad"}, NULL, {"*", "*ftedoom"},"Doom"},
|
// {"-doom", "doom", "FTE-Doom", {"doom.wad"}, NULL, {"*", "*ftedoom"},"Doom"},
|
||||||
|
@ -1554,7 +1558,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!Q_strcasecmp(ext, "bsp") || !Q_strcasecmp(ext, "map") || !Q_strcasecmp(ext, "hmp")) && !strncmp(name, "maps/", 5) && strncmp(name, "maps/b_", 7))
|
if ((!Q_strcasecmp(ext, "bsp") || !Q_strcasecmp(ext, "d3dbsp") || !Q_strcasecmp(ext, "map") || !Q_strcasecmp(ext, "hmp")) && !strncmp(name, "maps/", 5) && strncmp(name, "maps/b_", 7))
|
||||||
{
|
{
|
||||||
Q_snprintfz(link, sizeof(link), "\\tip\\Change Map\\map\\%s", name+5);
|
Q_snprintfz(link, sizeof(link), "\\tip\\Change Map\\map\\%s", name+5);
|
||||||
colour = "^4"; //disconnects
|
colour = "^4"; //disconnects
|
||||||
|
@ -1563,7 +1567,9 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
|
||||||
else if (!Q_strcasecmp(ext, "bsp") || !Q_strcasecmp(ext, "spr") || !Q_strcasecmp(ext, "sp2") || !Q_strcasecmp(ext, "mdl") || !Q_strcasecmp(ext, "md3") || !Q_strcasecmp(ext, "iqm") ||
|
else if (!Q_strcasecmp(ext, "bsp") || !Q_strcasecmp(ext, "spr") || !Q_strcasecmp(ext, "sp2") || !Q_strcasecmp(ext, "mdl") || !Q_strcasecmp(ext, "md3") || !Q_strcasecmp(ext, "iqm") ||
|
||||||
!Q_strcasecmp(ext, "vvm") || !Q_strcasecmp(ext, "psk") || !Q_strcasecmp(ext, "dpm") || !Q_strcasecmp(ext, "zym") || !Q_strcasecmp(ext, "md5mesh") ||
|
!Q_strcasecmp(ext, "vvm") || !Q_strcasecmp(ext, "psk") || !Q_strcasecmp(ext, "dpm") || !Q_strcasecmp(ext, "zym") || !Q_strcasecmp(ext, "md5mesh") ||
|
||||||
!Q_strcasecmp(ext, "mdx") || !Q_strcasecmp(ext, "md2") || !Q_strcasecmp(ext, "obj") || !Q_strcasecmp(ext, "mds") || !Q_strcasecmp(ext, "mdc") ||
|
!Q_strcasecmp(ext, "mdx") || !Q_strcasecmp(ext, "md2") || !Q_strcasecmp(ext, "obj") || !Q_strcasecmp(ext, "mds") || !Q_strcasecmp(ext, "mdc") ||
|
||||||
!Q_strcasecmp(ext, "md5anim") || !Q_strcasecmp(ext, "gltf") || !Q_strcasecmp(ext, "glb") || !Q_strcasecmp(ext, "ase") || !Q_strcasecmp(ext, "lwo"))
|
!Q_strcasecmp(ext, "md5anim") || !Q_strcasecmp(ext, "gltf") || !Q_strcasecmp(ext, "glb") || !Q_strcasecmp(ext, "ase") || !Q_strcasecmp(ext, "lwo") ||
|
||||||
|
((!Q_strncasecmp(name, "xmodel/", 7)||!Q_strncasecmp(name, "xanim/", 6)) && !Q_strcasecmp(ext, "")) //urgh
|
||||||
|
)
|
||||||
Q_snprintfz(link, sizeof(link), "\\tip\\Open in Model Viewer\\modelviewer\\%s", name);
|
Q_snprintfz(link, sizeof(link), "\\tip\\Open in Model Viewer\\modelviewer\\%s", name);
|
||||||
#endif
|
#endif
|
||||||
#ifdef TEXTEDITOR
|
#ifdef TEXTEDITOR
|
||||||
|
@ -1578,7 +1584,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
|
||||||
#endif
|
#endif
|
||||||
else if (!Q_strcasecmp(ext, "tga") || !Q_strcasecmp(ext, "png") || !Q_strcasecmp(ext, "jpg") || !Q_strcasecmp(ext, "jpeg")|| !Q_strcasecmp(ext, "lmp") || !Q_strcasecmp(ext, "ico") ||
|
else if (!Q_strcasecmp(ext, "tga") || !Q_strcasecmp(ext, "png") || !Q_strcasecmp(ext, "jpg") || !Q_strcasecmp(ext, "jpeg")|| !Q_strcasecmp(ext, "lmp") || !Q_strcasecmp(ext, "ico") ||
|
||||||
!Q_strcasecmp(ext, "pcx") || !Q_strcasecmp(ext, "bmp") || !Q_strcasecmp(ext, "dds") || !Q_strcasecmp(ext, "ktx") || !Q_strcasecmp(ext, "ktx2")|| !Q_strcasecmp(ext, "vtf") ||
|
!Q_strcasecmp(ext, "pcx") || !Q_strcasecmp(ext, "bmp") || !Q_strcasecmp(ext, "dds") || !Q_strcasecmp(ext, "ktx") || !Q_strcasecmp(ext, "ktx2")|| !Q_strcasecmp(ext, "vtf") ||
|
||||||
!Q_strcasecmp(ext, "astc")|| !Q_strcasecmp(ext, "htga")|| !Q_strcasecmp(ext, "exr") || !Q_strcasecmp(ext, "xcf") || !Q_strcasecmp(ext, "psd") ||
|
!Q_strcasecmp(ext, "astc")|| !Q_strcasecmp(ext, "htga")|| !Q_strcasecmp(ext, "exr") || !Q_strcasecmp(ext, "xcf") || !Q_strcasecmp(ext, "psd") || !Q_strcasecmp(ext, "iwi") ||
|
||||||
!Q_strcasecmp(ext, "pbm") || !Q_strcasecmp(ext, "ppm") || !Q_strcasecmp(ext, "pgm") || !Q_strcasecmp(ext, "pam") || !Q_strcasecmp(ext, "pfm") || !Q_strcasecmp(ext, "hdr") )
|
!Q_strcasecmp(ext, "pbm") || !Q_strcasecmp(ext, "ppm") || !Q_strcasecmp(ext, "pgm") || !Q_strcasecmp(ext, "pam") || !Q_strcasecmp(ext, "pfm") || !Q_strcasecmp(ext, "hdr") )
|
||||||
{
|
{
|
||||||
//FIXME: image replacements are getting in the way here.
|
//FIXME: image replacements are getting in the way here.
|
||||||
|
@ -8272,6 +8278,7 @@ void FS_RegisterDefaultFileSystems(void)
|
||||||
FS_RegisterFileSystemType(NULL, "pkz", FSZIP_LoadArchive, true); //q2pro uses a different extension
|
FS_RegisterFileSystemType(NULL, "pkz", FSZIP_LoadArchive, true); //q2pro uses a different extension
|
||||||
FS_RegisterFileSystemType(NULL, "pkx", FSZIP_LoadArchive, true); //q2xp naturally uses a different extension too... you'll be glad to know that yq2 uses pk3 instead. yay consistency - every engine uses something different!
|
FS_RegisterFileSystemType(NULL, "pkx", FSZIP_LoadArchive, true); //q2xp naturally uses a different extension too... you'll be glad to know that yq2 uses pk3 instead. yay consistency - every engine uses something different!
|
||||||
#endif
|
#endif
|
||||||
|
FS_RegisterFileSystemType(NULL, "iwd", FSZIP_LoadArchive, true); //cod2's variation.
|
||||||
FS_RegisterFileSystemType(NULL, "apk", FSZIP_LoadArchive, false); //android package
|
FS_RegisterFileSystemType(NULL, "apk", FSZIP_LoadArchive, false); //android package
|
||||||
FS_RegisterFileSystemType(NULL, "zip", FSZIP_LoadArchive, false); //regular zip file (don't automatically read from these, because it gets messy)
|
FS_RegisterFileSystemType(NULL, "zip", FSZIP_LoadArchive, false); //regular zip file (don't automatically read from these, because it gets messy)
|
||||||
FS_RegisterFileSystemType(NULL, "kpf", FSZIP_LoadArchive, true); //regular zip file (don't automatically read from these, because it gets messy)
|
FS_RegisterFileSystemType(NULL, "kpf", FSZIP_LoadArchive, true); //regular zip file (don't automatically read from these, because it gets messy)
|
||||||
|
|
|
@ -236,6 +236,7 @@ typedef struct shaderparsestate_s
|
||||||
const char *forcedshader;
|
const char *forcedshader;
|
||||||
unsigned int parseflags; //SPF_*
|
unsigned int parseflags; //SPF_*
|
||||||
qboolean droppass;
|
qboolean droppass;
|
||||||
|
unsigned int oldflags; //shader flags to revert to if the pass is dropped.
|
||||||
|
|
||||||
//for dpwater compat, used to generate a program
|
//for dpwater compat, used to generate a program
|
||||||
int dpwatertype;
|
int dpwatertype;
|
||||||
|
@ -3160,6 +3161,8 @@ shaderpass_t *Shaderpass_DefineMap(parsestate_t *ps, shaderpass_t *pass)
|
||||||
memset(pass, 0, sizeof(*pass));
|
memset(pass, 0, sizeof(*pass));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (pass->numMergedPasses>1)
|
||||||
|
pass = ps->s->passes+ps->s->numpasses-1; //nextbundle stuff.
|
||||||
else
|
else
|
||||||
pass->numMergedPasses = 1;
|
pass->numMergedPasses = 1;
|
||||||
return pass;
|
return pass;
|
||||||
|
@ -3178,6 +3181,14 @@ static void Shaderpass_Map (parsestate_t *ps, const char **ptr)
|
||||||
|
|
||||||
token = Shader_ParseSensString (ptr);
|
token = Shader_ParseSensString (ptr);
|
||||||
|
|
||||||
|
/*cod compat*/
|
||||||
|
if (!stricmp(token, "clamp"))
|
||||||
|
token = Shader_ParseSensString (ptr);
|
||||||
|
else if (!stricmp(token, "clampx"))
|
||||||
|
token = Shader_ParseSensString (ptr);
|
||||||
|
else if (!stricmp(token, "clampy"))
|
||||||
|
token = Shader_ParseSensString (ptr);
|
||||||
|
|
||||||
flags = Shader_SetImageFlags (ps, pass, &token, 0);
|
flags = Shader_SetImageFlags (ps, pass, &token, 0);
|
||||||
if (!Shaderpass_MapGen(ps, pass, token))
|
if (!Shaderpass_MapGen(ps, pass, token))
|
||||||
{
|
{
|
||||||
|
@ -3350,6 +3361,92 @@ static void Shaderpass_RTCW_AnimMap_nos3tc (parsestate_t *ps, const char **ptr)
|
||||||
Shaderpass_AnimMap(ps, ptr);
|
Shaderpass_AnimMap(ps, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Shader_BeginPass(parsestate_t *ps);
|
||||||
|
static void Shader_EndPass(parsestate_t *ps);
|
||||||
|
static void Shaderpass_CoD_NextBundle (parsestate_t *ps, const char **ptr)
|
||||||
|
{ //in a pass... end it and start the next. cos annoying.
|
||||||
|
shaderpass_t *basepass = ps->pass;
|
||||||
|
shaderpass_t *newpass;
|
||||||
|
if (!basepass->numMergedPasses)
|
||||||
|
basepass->numMergedPasses = 1; //its explicit...
|
||||||
|
if (ps->s->numpasses == SHADER_PASS_MAX || ps->s->numpasses == SHADER_TMU_MAX)
|
||||||
|
ps->droppass = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
basepass->numMergedPasses++;
|
||||||
|
ps->s->numpasses++;
|
||||||
|
}
|
||||||
|
newpass = ps->s->passes+ps->s->numpasses-1;
|
||||||
|
memset(newpass, 0, sizeof(*newpass));
|
||||||
|
newpass->numMergedPasses++;
|
||||||
|
|
||||||
|
newpass->tcgen = TC_GEN_UNSPECIFIED;
|
||||||
|
newpass->shaderbits |= SBITS_SRCBLEND_DST_COLOR | SBITS_DSTBLEND_ZERO;
|
||||||
|
newpass->shaderbits |= SBITS_DEPTHFUNC_EQUAL;
|
||||||
|
/*
|
||||||
|
qboolean depthwrite = !!(ps->pass->shaderbits & SBITS_MISC_DEPTHWRITE);
|
||||||
|
qboolean dropping = ps->droppass;
|
||||||
|
Shader_EndPass(ps);
|
||||||
|
|
||||||
|
Shader_BeginPass(ps);
|
||||||
|
ps->droppass = dropping;
|
||||||
|
//make it modulate.
|
||||||
|
ps->pass->shaderbits |= SBITS_SRCBLEND_DST_COLOR | SBITS_DSTBLEND_ZERO;
|
||||||
|
if (depthwrite) //and if the last one is doing weird alphatest crap, copy its depthfunc status.
|
||||||
|
ps->pass->shaderbits |= SBITS_DEPTHFUNC_EQUAL;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
static void Shaderpass_CoD_Requires (parsestate_t *ps, const char **ptr)
|
||||||
|
{
|
||||||
|
if (!Shader_EvaluateCondition(ps->s, ptr))
|
||||||
|
ps->droppass = true;
|
||||||
|
}
|
||||||
|
static void Shaderpass_CoD_texEnvCombine (parsestate_t *ps, const char **ptr)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
char *token;
|
||||||
|
while (*(token = COM_ParseExt (&ps->ptr, true, true)))
|
||||||
|
{ //extra parsing to even out this unexpected brace without extra warnings.
|
||||||
|
if (token[0] == '}')
|
||||||
|
depth--;
|
||||||
|
else if (token[0] == '{')
|
||||||
|
depth++; //crap.
|
||||||
|
if (!depth)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ps->droppass = true;
|
||||||
|
}
|
||||||
|
static void Shaderpass_CoD_nvRegCombiners (parsestate_t *ps, const char **ptr)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
char *token;
|
||||||
|
while (*(token = COM_ParseExt (&ps->ptr, true, true)))
|
||||||
|
{ //extra parsing to even out this unexpected brace without extra warnings.
|
||||||
|
if (token[0] == '}')
|
||||||
|
depth--;
|
||||||
|
else if (token[0] == '{')
|
||||||
|
depth++; //crap.
|
||||||
|
if (!depth)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ps->droppass = true;
|
||||||
|
}
|
||||||
|
static void Shaderpass_CoD_atiFragmentShader (parsestate_t *ps, const char **ptr)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
char *token;
|
||||||
|
while (*(token = COM_ParseExt (&ps->ptr, true, true)))
|
||||||
|
{ //extra parsing to even out this unexpected brace without extra warnings.
|
||||||
|
if (token[0] == '}')
|
||||||
|
depth--;
|
||||||
|
else if (token[0] == '{')
|
||||||
|
depth++; //crap.
|
||||||
|
if (!depth)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ps->droppass = true;
|
||||||
|
}
|
||||||
|
|
||||||
static void Shaderpass_SLProgramName (shader_t *shader, shaderpass_t *pass, const char **ptr, int qrtype)
|
static void Shaderpass_SLProgramName (shader_t *shader, shaderpass_t *pass, const char **ptr, int qrtype)
|
||||||
{
|
{
|
||||||
/*accepts:
|
/*accepts:
|
||||||
|
@ -3433,7 +3530,8 @@ static void Shaderpass_RGBGen (parsestate_t *ps, const char **ptr)
|
||||||
pass->rgbgen = RGB_GEN_ENTITY_LIGHTING_DIFFUSE;
|
pass->rgbgen = RGB_GEN_ENTITY_LIGHTING_DIFFUSE;
|
||||||
else if (!Q_stricmp (token, "exactvertex"))
|
else if (!Q_stricmp (token, "exactvertex"))
|
||||||
pass->rgbgen = RGB_GEN_VERTEX_EXACT;
|
pass->rgbgen = RGB_GEN_VERTEX_EXACT;
|
||||||
else if (!Q_stricmp (token, "const") || !Q_stricmp (token, "constant"))
|
else if (!Q_stricmp (token, "const") || !Q_stricmp (token, "constant")
|
||||||
|
|| !Q_stricmp (token, "constLighting"))
|
||||||
{
|
{
|
||||||
pass->rgbgen = RGB_GEN_CONST;
|
pass->rgbgen = RGB_GEN_CONST;
|
||||||
pass->rgbgen_func.type = SHADER_FUNC_CONSTANT;
|
pass->rgbgen_func.type = SHADER_FUNC_CONSTANT;
|
||||||
|
@ -3587,6 +3685,9 @@ static void Shaderpass_BlendFunc (parsestate_t *ps, const char **ptr)
|
||||||
shaderpass_t *pass = ps->pass;
|
shaderpass_t *pass = ps->pass;
|
||||||
char *token;
|
char *token;
|
||||||
|
|
||||||
|
if (pass->numMergedPasses>1)
|
||||||
|
pass = ps->s->passes+ps->s->numpasses-1; //nextbundle stuff.
|
||||||
|
|
||||||
//reset to defaults
|
//reset to defaults
|
||||||
pass->shaderbits &= ~(SBITS_BLEND_BITS);
|
pass->shaderbits &= ~(SBITS_BLEND_BITS);
|
||||||
pass->stagetype = ST_AMBIENT;
|
pass->stagetype = ST_AMBIENT;
|
||||||
|
@ -3699,6 +3800,9 @@ static void Shaderpass_TcMod (parsestate_t *ps, const char **ptr)
|
||||||
tcmod_t *tcmod;
|
tcmod_t *tcmod;
|
||||||
char *token;
|
char *token;
|
||||||
|
|
||||||
|
if (pass->numMergedPasses>1)
|
||||||
|
pass = ps->s->passes+ps->s->numpasses-1; //nextbundle stuff.
|
||||||
|
|
||||||
if (pass->numtcmods >= SHADER_MAX_TC_MODS)
|
if (pass->numtcmods >= SHADER_MAX_TC_MODS)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -3853,6 +3957,9 @@ static void Shaderpass_TcGen (parsestate_t *ps, const char **ptr)
|
||||||
shaderpass_t *pass = ps->pass;
|
shaderpass_t *pass = ps->pass;
|
||||||
char *token;
|
char *token;
|
||||||
|
|
||||||
|
if (pass->numMergedPasses>1)
|
||||||
|
pass = ps->s->passes+ps->s->numpasses-1; //nextbundle stuff.
|
||||||
|
|
||||||
token = Shader_ParseString ( ptr );
|
token = Shader_ParseString ( ptr );
|
||||||
if ( !Q_stricmp (token, "base") ) {
|
if ( !Q_stricmp (token, "base") ) {
|
||||||
pass->tcgen = TC_GEN_BASE;
|
pass->tcgen = TC_GEN_BASE;
|
||||||
|
@ -4073,6 +4180,12 @@ static shaderkey_t shaderpasskeys[] =
|
||||||
// {"greyscale", Shaderpass_QF_Greyscale, "qf"},
|
// {"greyscale", Shaderpass_QF_Greyscale, "qf"},
|
||||||
// {"skip", Shaderpass_QF_Skip, "qf"},
|
// {"skip", Shaderpass_QF_Skip, "qf"},
|
||||||
|
|
||||||
|
{"nextbundle", Shaderpass_CoD_NextBundle, "cod"},
|
||||||
|
{"requires", Shaderpass_CoD_Requires, "cod"},
|
||||||
|
{"texEnvCombine", Shaderpass_CoD_texEnvCombine, "cod"},
|
||||||
|
{"nvRegCombiners", Shaderpass_CoD_nvRegCombiners, "cod"},
|
||||||
|
{"atiFragmentShader", Shaderpass_CoD_atiFragmentShader, "cod"},
|
||||||
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4775,14 +4888,12 @@ static qboolean Shader_Conditional_Read(parsestate_t *ps, struct scondinfo_s *co
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Shader_Readpass (parsestate_t *ps)
|
static void Shader_BeginPass(parsestate_t *ps)
|
||||||
{
|
{
|
||||||
shader_t *shader = ps->s;
|
shader_t *shader = ps->s;
|
||||||
const char *token;
|
|
||||||
shaderpass_t *pass;
|
shaderpass_t *pass;
|
||||||
static shader_t dummy;
|
static shader_t dummy;
|
||||||
struct scondinfo_s cond = {0};
|
ps->oldflags = shader->flags;
|
||||||
unsigned int oldflags = shader->flags;
|
|
||||||
|
|
||||||
if ( shader->numpasses >= SHADER_PASS_MAX )
|
if ( shader->numpasses >= SHADER_PASS_MAX )
|
||||||
{
|
{
|
||||||
|
@ -4812,25 +4923,11 @@ static void Shader_Readpass (parsestate_t *ps)
|
||||||
pass->flags |= SHADER_PASS_NOMIPMAP;
|
pass->flags |= SHADER_PASS_NOMIPMAP;
|
||||||
|
|
||||||
ps->pass = pass;
|
ps->pass = pass;
|
||||||
|
|
||||||
while ( ps->ptr )
|
|
||||||
{
|
|
||||||
token = COM_ParseExt (&ps->ptr, true, true);
|
|
||||||
|
|
||||||
if ( !token[0] )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
else if (!Shader_Conditional_Read(ps, &cond, token, &ps->ptr))
|
static void Shader_EndPass(parsestate_t *ps)
|
||||||
{
|
{
|
||||||
if ( token[0] == '}' )
|
shader_t *shader = ps->s;
|
||||||
break;
|
shaderpass_t *pass = ps->pass;
|
||||||
else if (token[0] == '{')
|
|
||||||
Con_Printf(CON_WARNING"%s: unexpected indentation in %s\n", ps->sourcename, shader->name);
|
|
||||||
else if ( Shader_Parsetok (ps, shaderpasskeys, token) )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pass->alphagen == ALPHA_GEN_UNDEFINED)
|
if (pass->alphagen == ALPHA_GEN_UNDEFINED)
|
||||||
pass->alphagen = ALPHA_GEN_IDENTITY;
|
pass->alphagen = ALPHA_GEN_IDENTITY;
|
||||||
|
@ -4839,11 +4936,6 @@ static void Shader_Readpass (parsestate_t *ps)
|
||||||
if (!pass->numMergedPasses)
|
if (!pass->numMergedPasses)
|
||||||
pass->numMergedPasses = 1;
|
pass->numMergedPasses = 1;
|
||||||
|
|
||||||
if (cond.depth)
|
|
||||||
{
|
|
||||||
Con_Printf("if statements without endif in shader %s\n", shader->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pass->tcgen == TC_GEN_UNSPECIFIED)
|
if (pass->tcgen == TC_GEN_UNSPECIFIED)
|
||||||
pass->tcgen = TC_GEN_BASE;
|
pass->tcgen = TC_GEN_BASE;
|
||||||
|
|
||||||
|
@ -4926,10 +5018,57 @@ static void Shader_Readpass (parsestate_t *ps)
|
||||||
Shader_FreePass (pass+--pass->numMergedPasses);
|
Shader_FreePass (pass+--pass->numMergedPasses);
|
||||||
shader->numpasses--;
|
shader->numpasses--;
|
||||||
}
|
}
|
||||||
shader->flags = oldflags;
|
shader->flags = ps->oldflags;
|
||||||
}
|
}
|
||||||
ps->pass = NULL;
|
ps->pass = NULL;
|
||||||
}
|
}
|
||||||
|
static void Shader_Readpass (parsestate_t *ps)
|
||||||
|
{
|
||||||
|
shader_t *shader = ps->s;
|
||||||
|
const char *token;
|
||||||
|
struct scondinfo_s cond = {0};
|
||||||
|
|
||||||
|
Shader_BeginPass(ps);
|
||||||
|
|
||||||
|
while ( ps->ptr )
|
||||||
|
{
|
||||||
|
token = COM_ParseExt (&ps->ptr, true, true);
|
||||||
|
|
||||||
|
if ( !token[0] )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (!Shader_Conditional_Read(ps, &cond, token, &ps->ptr))
|
||||||
|
{
|
||||||
|
if ( token[0] == '}' )
|
||||||
|
break;
|
||||||
|
else if (token[0] == '{')
|
||||||
|
{
|
||||||
|
int depth = 1;
|
||||||
|
Con_Printf(CON_WARNING"%s: unexpected indentation in %s\n", ps->sourcename, shader->name);
|
||||||
|
while (*(token = COM_ParseExt (&ps->ptr, true, true)))
|
||||||
|
{ //extra parsing to even out this unexpected brace without extra warnings.
|
||||||
|
if (token[0] == '}')
|
||||||
|
{
|
||||||
|
if (depth--==0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (token[0] == '{')
|
||||||
|
depth++; //crap.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( Shader_Parsetok (ps, shaderpasskeys, token) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cond.depth)
|
||||||
|
{
|
||||||
|
Con_Printf("if statements without endif in shader %s\n", shader->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader_EndPass(ps);
|
||||||
|
}
|
||||||
|
|
||||||
//we've read the first token, now make sense of it and any args
|
//we've read the first token, now make sense of it and any args
|
||||||
static qboolean Shader_Parsetok(parsestate_t *ps, shaderkey_t *keys, const char *token)
|
static qboolean Shader_Parsetok(parsestate_t *ps, shaderkey_t *keys, const char *token)
|
||||||
|
@ -5013,7 +5152,7 @@ static void Shader_SetPassFlush (shaderpass_t *pass, shaderpass_t *pass2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*rgbgen must be identity too except if the later pass is identity_ligting, in which case all is well and we can switch the first pass to identity_lighting instead*/
|
/*rgbgen must be identity too except if the later pass is identity_ligting, in which case all is well and we can switch the first pass to identity_lighting instead*/
|
||||||
if (pass2->rgbgen == RGB_GEN_IDENTITY_LIGHTING && (pass2->blendmode == PBM_OVERBRIGHT || pass2->blendmode == PBM_MODULATE) && pass->rgbgen == RGB_GEN_IDENTITY)
|
if (pass2->rgbgen == RGB_GEN_IDENTITY_LIGHTING && (pass2->blendmode == PBM_OVERBRIGHT || pass2->blendmode == PBM_MODULATE) && (pass->rgbgen == RGB_GEN_IDENTITY||pass->rgbgen == RGB_GEN_VERTEX_EXACT))
|
||||||
{
|
{
|
||||||
if (pass->blendmode == PBM_REPLACE)
|
if (pass->blendmode == PBM_REPLACE)
|
||||||
pass->blendmode = PBM_REPLACELIGHT;
|
pass->blendmode = PBM_REPLACELIGHT;
|
||||||
|
@ -5961,7 +6100,7 @@ void QDECL R_BuildDefaultTexnums(texnums_t *src, shader_t *shader, unsigned int
|
||||||
unsigned int a, aframes;
|
unsigned int a, aframes;
|
||||||
strcpy(imagename, shader->name);
|
strcpy(imagename, shader->name);
|
||||||
h = strchr(imagename, '#');
|
h = strchr(imagename, '#');
|
||||||
if (h)
|
if (h && !strchr(imagename, '@'))
|
||||||
*h = 0;
|
*h = 0;
|
||||||
if (*imagename == '/' || strchr(imagename, ':'))
|
if (*imagename == '/' || strchr(imagename, ':'))
|
||||||
{ //this is not security. this is anti-spam for the verbose security in the filesystem code.
|
{ //this is not security. this is anti-spam for the verbose security in the filesystem code.
|
||||||
|
@ -6409,7 +6548,7 @@ shader_t *Mod_RegisterBasicShader(struct model_s *mod, const char *texname, unsi
|
||||||
char mapbase[64];
|
char mapbase[64];
|
||||||
if (shadertext)
|
if (shadertext)
|
||||||
s = R_RegisterShader(texname, usageflags, shadertext);
|
s = R_RegisterShader(texname, usageflags, shadertext);
|
||||||
else if (mod->type == mod_brush)
|
else if (mod->type != mod_brush)
|
||||||
s = R_RegisterCustom(mod, texname, usageflags, Shader_DefaultSkin, NULL);
|
s = R_RegisterCustom(mod, texname, usageflags, Shader_DefaultSkin, NULL);
|
||||||
else
|
else
|
||||||
s = R_RegisterCustom(mod, texname, usageflags, Shader_DefaultBSPLM, NULL);
|
s = R_RegisterCustom(mod, texname, usageflags, Shader_DefaultBSPLM, NULL);
|
||||||
|
@ -7410,7 +7549,8 @@ static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename)
|
||||||
const char *buf = NULL;
|
const char *buf = NULL;
|
||||||
shadercachefile_t *sourcefile = NULL;
|
shadercachefile_t *sourcefile = NULL;
|
||||||
const char *file;
|
const char *file;
|
||||||
const char *token;
|
const char *token=".";
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (!strchr(parsename, ':'))
|
if (!strchr(parsename, ':'))
|
||||||
{
|
{
|
||||||
|
@ -7419,7 +7559,6 @@ static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename)
|
||||||
if (!strcmp(token, ".mat") || !*token)
|
if (!strcmp(token, ".mat") || !*token)
|
||||||
{
|
{
|
||||||
char shaderfile[MAX_QPATH];
|
char shaderfile[MAX_QPATH];
|
||||||
size_t i;
|
|
||||||
if (!*token)
|
if (!*token)
|
||||||
{
|
{
|
||||||
for (i = 0; i < materialloader_count; i++)
|
for (i = 0; i < materialloader_count; i++)
|
||||||
|
@ -7471,6 +7610,15 @@ static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*token)
|
||||||
|
{
|
||||||
|
for (i = 0; i < materialloader_count; i++)
|
||||||
|
{
|
||||||
|
if (materialloader[i].funcs->ReadMaterial(ps, parsename, Shader_LoadMaterialString))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void R_UnloadShader(shader_t *shader)
|
void R_UnloadShader(shader_t *shader)
|
||||||
|
|
|
@ -435,13 +435,15 @@ static int QDECL ShowMapList (const char *name, qofs_t flags, time_t mtime, void
|
||||||
if (!strcmp(ext, ".gz") || !strcmp(ext, ".xz"))
|
if (!strcmp(ext, ".gz") || !strcmp(ext, ".xz"))
|
||||||
ext = COM_GetFileExtension (name+5, ext); //.gz files should be listed too.
|
ext = COM_GetFileExtension (name+5, ext); //.gz files should be listed too.
|
||||||
|
|
||||||
if (!strcmp(ext, ".bsp"))
|
if (!strcmp(ext, ".bsp") || !Q_strcasecmp(ext, ".d3dbsp"))
|
||||||
{
|
{
|
||||||
ext = ""; //hide it
|
ext = ""; //hide it
|
||||||
cmd = stripped; //omit it, might as well. should give less confusing mapname serverinfo etc.
|
cmd = stripped; //omit it, might as well. should give less confusing mapname serverinfo etc.
|
||||||
}
|
}
|
||||||
else if (!Q_strcasecmp(ext, ".bsp") || !Q_strcasecmp(ext, ".bsp.gz") || !Q_strcasecmp(ext, ".bsp.xz"))
|
else if (!Q_strcasecmp(ext, ".bsp") || !Q_strcasecmp(ext, ".bsp.gz") || !Q_strcasecmp(ext, ".bsp.xz"))
|
||||||
;
|
;
|
||||||
|
else if (!Q_strcasecmp(ext, ".d3dbsp") || !Q_strcasecmp(ext, ".d3dbsp.gz") || !Q_strcasecmp(ext, ".d3dbsp.xz"))
|
||||||
|
; //cod2 compat. vile.
|
||||||
#ifdef TERRAIN
|
#ifdef TERRAIN
|
||||||
else if (!Q_strcasecmp(ext, ".map") || !Q_strcasecmp(ext, ".map.gz") || !Q_strcasecmp(ext, ".hmp"))
|
else if (!Q_strcasecmp(ext, ".map") || !Q_strcasecmp(ext, ".map.gz") || !Q_strcasecmp(ext, ".hmp"))
|
||||||
;
|
;
|
||||||
|
@ -547,6 +549,7 @@ static void SV_Map_c(int argn, const char *partial, struct xcommandargcompletion
|
||||||
{
|
{
|
||||||
//FIXME: maps/mapname#modifier.ent
|
//FIXME: maps/mapname#modifier.ent
|
||||||
COM_EnumerateFiles(va("maps/%s*.bsp", partial), CompleteMapList, ctx);
|
COM_EnumerateFiles(va("maps/%s*.bsp", partial), CompleteMapList, ctx);
|
||||||
|
COM_EnumerateFiles(va("maps/%s*.d3dbsp", partial), CompleteMapList, ctx);
|
||||||
COM_EnumerateFiles(va("maps/%s*.bsp.gz", partial), CompleteMapListExt, ctx);
|
COM_EnumerateFiles(va("maps/%s*.bsp.gz", partial), CompleteMapListExt, ctx);
|
||||||
COM_EnumerateFiles(va("maps/%s*.bsp.xz", partial), CompleteMapListExt, ctx);
|
COM_EnumerateFiles(va("maps/%s*.bsp.xz", partial), CompleteMapListExt, ctx);
|
||||||
COM_EnumerateFiles(va("maps/%s*.map", partial), CompleteMapListExt, ctx);
|
COM_EnumerateFiles(va("maps/%s*.map", partial), CompleteMapListExt, ctx);
|
||||||
|
@ -557,6 +560,7 @@ static void SV_Map_c(int argn, const char *partial, struct xcommandargcompletion
|
||||||
COM_EnumerateFiles(va("maps/%s*.ent", partial), CompleteMapListEnt, ctx);
|
COM_EnumerateFiles(va("maps/%s*.ent", partial), CompleteMapListEnt, ctx);
|
||||||
|
|
||||||
COM_EnumerateFiles(va("maps/%s*/*.bsp", partial), CompleteMapList, ctx);
|
COM_EnumerateFiles(va("maps/%s*/*.bsp", partial), CompleteMapList, ctx);
|
||||||
|
COM_EnumerateFiles(va("maps/%s*/*.d3dbsp", partial), CompleteMapList, ctx);
|
||||||
COM_EnumerateFiles(va("maps/%s*/*.bsp.gz", partial), CompleteMapListExt, ctx);
|
COM_EnumerateFiles(va("maps/%s*/*.bsp.gz", partial), CompleteMapListExt, ctx);
|
||||||
COM_EnumerateFiles(va("maps/%s*/*.bsp.xz", partial), CompleteMapListExt, ctx);
|
COM_EnumerateFiles(va("maps/%s*/*.bsp.xz", partial), CompleteMapListExt, ctx);
|
||||||
COM_EnumerateFiles(va("maps/%s*/*.map", partial), CompleteMapListExt, ctx);
|
COM_EnumerateFiles(va("maps/%s*/*.map", partial), CompleteMapListExt, ctx);
|
||||||
|
@ -949,7 +953,7 @@ void SV_Map_f (void)
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
char *exts[] = {"%s", "maps/%s", "maps/%s.bsp", "maps/%s.bsp.gz", "maps/%s.bsp.xz", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ /*"maps/%s.ent",*/ NULL};
|
char *exts[] = {"%s", "maps/%s", "maps/%s.bsp", "maps/%s.bsp.gz", "maps/%s.bsp.xz", "maps/%s.d3dbsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ /*"maps/%s.ent",*/ NULL};
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
for (i = 0; exts[i]; i++)
|
for (i = 0; exts[i]; i++)
|
||||||
|
|
|
@ -1013,7 +1013,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
|
||||||
{
|
{
|
||||||
//.map is commented out because quite frankly, they're a bit annoying when the engine loads the gpled start.map when really you wanted to just play the damn game intead of take it apart.
|
//.map is commented out because quite frankly, they're a bit annoying when the engine loads the gpled start.map when really you wanted to just play the damn game intead of take it apart.
|
||||||
//if you want to load a .map, just use 'map foo.map' instead.
|
//if you want to load a .map, just use 'map foo.map' instead.
|
||||||
char *exts[] = {"%s", "maps/%s", "maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ "maps/%s.bsp.gz", "maps/%s.bsp.xz", NULL}, *e;
|
char *exts[] = {"%s", "maps/%s", "maps/%s.bsp", "maps/%s.d3dbsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ "maps/%s.bsp.gz", "maps/%s.bsp.xz", NULL}, *e;
|
||||||
int depth, bestdepth = FDEPTH_MISSING;
|
int depth, bestdepth = FDEPTH_MISSING;
|
||||||
flocation_t loc;
|
flocation_t loc;
|
||||||
time_t filetime;
|
time_t filetime;
|
||||||
|
|
|
@ -515,6 +515,14 @@ $(PLUG_PREFIX)hl2$(PLUG_NATIVE_EXT): hl2/fs_vpk.c hl2/img_vtf.c hl2/mod_hl2.c hl
|
||||||
NATIVE_PLUGINS+=hl2
|
NATIVE_PLUGINS+=hl2
|
||||||
######################################
|
######################################
|
||||||
|
|
||||||
|
######################################
|
||||||
|
#for compat with cod's file formats
|
||||||
|
$(PLUG_PREFIX)cod$(PLUG_NATIVE_EXT): cod/codmod.c cod/codbsp.c cod/codmat.c cod/codiwi.c plugin.c
|
||||||
|
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -DMULTITHREAD -o $@ -shared $(PLUG_CFLAGS) $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS)
|
||||||
|
$(call EMBEDMETA,cod,$@,CoD Formats,Provides support for various formats used by Call of Duty.)
|
||||||
|
NATIVE_PLUGINS+=cod
|
||||||
|
######################################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
all: $(foreach FOO,$(NATIVE_PLUGINS), $(PLUG_PREFIX)$(FOO)$(PLUG_NATIVE_EXT))
|
all: $(foreach FOO,$(NATIVE_PLUGINS), $(PLUG_PREFIX)$(FOO)$(PLUG_NATIVE_EXT))
|
||||||
|
|
1863
plugins/cod/codbsp.c
Normal file
1863
plugins/cod/codbsp.c
Normal file
File diff suppressed because it is too large
Load diff
119
plugins/cod/codiwi.c
Normal file
119
plugins/cod/codiwi.c
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#include "../plugin.h"
|
||||||
|
|
||||||
|
static plugimagefuncs_t *imagefuncs;
|
||||||
|
static struct pendingtextureinfo *Image_ReadIWIFile(unsigned int imgflags, const char *fname, qbyte *filedata, size_t filesize)
|
||||||
|
{
|
||||||
|
if (filesize >= 12 && filedata[0]=='I'&&filedata[1]=='W'&&filedata[2]=='i' && (filedata[3]==5/*cod2*/||filedata[3]==6/*cod4*/))
|
||||||
|
{
|
||||||
|
static const enum uploadfmt fmts[] = {PTI_INVALID/*0*/, PTI_RGBA8/*1*/, PTI_RGB8/*2*/, PTI_L8A8/*3, VALIDATE!*/, PTI_INVALID/*4,PTI_A8*/, PTI_INVALID/*5*/,PTI_INVALID/*6*/,PTI_INVALID/*7*/,PTI_INVALID/*8*/,PTI_INVALID/*9*/,PTI_INVALID/*10*/,PTI_BC1_RGBA/*11*/, PTI_BC2_RGBA/*12*/, PTI_BC3_RGBA/*13*/};
|
||||||
|
enum uploadfmt fmt = PTI_INVALID;
|
||||||
|
unsigned int bb,bw,bh,bd;
|
||||||
|
unsigned int iw,ih,id, l;
|
||||||
|
struct pendingtextureinfo *mips;
|
||||||
|
unsigned int offsets[4];
|
||||||
|
qbyte *end = filedata+filesize;
|
||||||
|
enum {
|
||||||
|
IWI_STANDARD=0,
|
||||||
|
IWI_MIPLESS=3,
|
||||||
|
IWI_CUBEMAP=6,
|
||||||
|
// IWI_NORMALMAP=0x20,
|
||||||
|
// IWI_UNKNOWN=0x40,
|
||||||
|
// IWI_UNKNOWN=0x80,
|
||||||
|
} usage = filedata[5];
|
||||||
|
if (filedata[4] < countof(fmts))
|
||||||
|
fmt = fmts[filedata[4]];
|
||||||
|
if (fmt == PTI_INVALID)
|
||||||
|
{ //bail. with warning
|
||||||
|
Con_Printf(CON_WARNING"Image_ReadIWIFile(%s): unsupported iwi pixelformat %x\n", fname, filedata[4]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
iw = filedata[6] | (filedata[7]<<8);
|
||||||
|
ih = filedata[8] | (filedata[9]<<8);
|
||||||
|
id = filedata[10] | (filedata[11]<<8);
|
||||||
|
|
||||||
|
imagefuncs->BlockSizeForEncoding(fmt, &bb, &bw, &bh, &bd);
|
||||||
|
if (!bb)
|
||||||
|
{
|
||||||
|
Con_Printf(CON_WARNING"Image_ReadIWIFile(%s): unsupported fte pixelformat %x(%i)\n", fname, filedata[4], fmt);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mips = plugfuncs->Malloc(sizeof(*mips));
|
||||||
|
mips->encoding = fmt;
|
||||||
|
if ((filedata[5]&0xf) == IWI_CUBEMAP && id==1)
|
||||||
|
{
|
||||||
|
mips->type = PTI_CUBE;
|
||||||
|
id *= 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mips->type = (id>1)?PTI_3D:PTI_2D;
|
||||||
|
mips->extrafree = filedata;
|
||||||
|
filedata += 12;
|
||||||
|
for (l = 0; l < countof(offsets); l++, filedata+=4)
|
||||||
|
offsets[l] = filedata[0] | (filedata[1]<<8) | (filedata[2]<<16) | (filedata[3]<<24); //dunno what this 4 values are for. looks like descending ends?
|
||||||
|
if (mips->type != PTI_2D || (usage&0xf)==IWI_MIPLESS)
|
||||||
|
mips->mipcount = l = 1;
|
||||||
|
else for (l = 0; l < countof(mips->mip); l++)
|
||||||
|
{
|
||||||
|
if ((iw >> l) || (ih >> l) || (id >> l))
|
||||||
|
mips->mipcount++;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//these are smallest to biggest.
|
||||||
|
while (l --> 0)
|
||||||
|
{
|
||||||
|
unsigned int w = iw>>l;
|
||||||
|
unsigned int h = ih>>l;
|
||||||
|
unsigned int d = (mips->type==PTI_3D)?id>>l:id;
|
||||||
|
size_t datasize;
|
||||||
|
if (!w && !h && ((mips->type==PTI_3D)?!d:true))
|
||||||
|
break;
|
||||||
|
if (!w)
|
||||||
|
w = 1;
|
||||||
|
if (!h)
|
||||||
|
h = 1;
|
||||||
|
if (!d)
|
||||||
|
d = 1;
|
||||||
|
datasize = ((w+bw-1)/bw) * ((h+bh-1)/bh) * ((d+bd-1)/bd) * bb;
|
||||||
|
|
||||||
|
if (filedata + datasize > end)
|
||||||
|
{
|
||||||
|
Con_Printf(CON_WARNING"%s: truncated\n", fname);
|
||||||
|
Con_Printf("%s: %#x\n", fname, usage);
|
||||||
|
plugfuncs->Free(mips);
|
||||||
|
return NULL; //doesn't fit...
|
||||||
|
}
|
||||||
|
mips->mip[l].width = w;
|
||||||
|
mips->mip[l].height = h;
|
||||||
|
mips->mip[l].depth = d;
|
||||||
|
mips->mip[l].data = filedata;
|
||||||
|
mips->mip[l].datasize = datasize;
|
||||||
|
mips->mip[l].needfree = false;
|
||||||
|
filedata += datasize;
|
||||||
|
}
|
||||||
|
if (filedata != end)
|
||||||
|
{
|
||||||
|
Con_Printf(CON_WARNING"%s: trailing data\n", fname);
|
||||||
|
Con_Printf("%s: %#x\n", fname, usage);
|
||||||
|
plugfuncs->Free(mips);
|
||||||
|
return NULL; //doesn't fit...
|
||||||
|
}
|
||||||
|
return mips;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static plugimageloaderfuncs_t iwifuncs =
|
||||||
|
{
|
||||||
|
"InfinityWard Image",
|
||||||
|
sizeof(struct pendingtextureinfo),
|
||||||
|
false,
|
||||||
|
Image_ReadIWIFile,
|
||||||
|
};
|
||||||
|
qboolean IWI_Init(void)
|
||||||
|
{
|
||||||
|
imagefuncs = plugfuncs->GetEngineInterface(plugimagefuncs_name, sizeof(*imagefuncs));
|
||||||
|
if (!imagefuncs)
|
||||||
|
return false;
|
||||||
|
return plugfuncs->ExportInterface(plugimageloaderfuncs_name, &iwifuncs, sizeof(iwifuncs));
|
||||||
|
}
|
244
plugins/cod/codmat.c
Normal file
244
plugins/cod/codmat.c
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
#include "../plugin.h"
|
||||||
|
#include "shader.h"
|
||||||
|
typedef struct shaderparsestate_s parsestate_t;
|
||||||
|
static plugfsfuncs_t *fsfuncs;
|
||||||
|
|
||||||
|
static qboolean COD2_DecodeMaterial(parsestate_t *ps, const char *filename, void (*LoadMaterialString)(parsestate_t *ps, const char *script))
|
||||||
|
{
|
||||||
|
size_t sz;
|
||||||
|
qbyte *base = fsfuncs->LoadFile(va("materials/%s", filename), &sz);
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int ofs_materialname; //usually matches filename. dunno why this needs to be here. for aliases? does the qbsp read this instead?
|
||||||
|
unsigned int ofs_texturename; //simplification for tools? dunno.
|
||||||
|
unsigned int z1;
|
||||||
|
qbyte unk10;
|
||||||
|
qbyte sort; //sort:
|
||||||
|
//0x00: distortion
|
||||||
|
//0x01: opaquewater
|
||||||
|
//0x02: boathull
|
||||||
|
//0x03: opaque
|
||||||
|
//0x04: sky
|
||||||
|
//0x04: skybox_sunmoon
|
||||||
|
//0x06: skybox_clouds
|
||||||
|
//0x08: decal_bottom1
|
||||||
|
//0x09: decal_bottom2
|
||||||
|
//0x0a: decal_bottom3
|
||||||
|
//0x0b: decal_world
|
||||||
|
//0x0c: decal_middle1
|
||||||
|
//0x0d: decal_middle2
|
||||||
|
//0x0e: decal_middle3
|
||||||
|
//0x0f: decal_gunimpact
|
||||||
|
//0x10: decal_top1
|
||||||
|
//0x11: decal_top2
|
||||||
|
//0x12: decal_top3
|
||||||
|
//0x12: decal_multiplicative
|
||||||
|
//0x14: banner
|
||||||
|
//0x15: hair
|
||||||
|
//0x16: underwater
|
||||||
|
//0x17: transparentwater
|
||||||
|
//0x18: corona
|
||||||
|
//0x19: windowinside
|
||||||
|
//0x1a: windowoutside
|
||||||
|
//0x1b: blend
|
||||||
|
//0x1c: viewmodel
|
||||||
|
qbyte unk12;
|
||||||
|
qbyte unk13;
|
||||||
|
unsigned int z2;
|
||||||
|
unsigned short unk2[2];
|
||||||
|
unsigned int unk3;
|
||||||
|
unsigned short width, height;
|
||||||
|
unsigned int z3;
|
||||||
|
unsigned int surfaceflags; //lower bits seem like they might be wrong. upper bits are consistentish with cod1 surfaceflags though.
|
||||||
|
unsigned int contentbits; //pure guess. probably wrong.
|
||||||
|
unsigned int blendbits; //0x00ff00ff bits are src/dst color/alpha blendfuncs matching the D3DBLEND enum.
|
||||||
|
unsigned int unk7;
|
||||||
|
unsigned int unk8;
|
||||||
|
unsigned int ofs_program;
|
||||||
|
unsigned int ofs_table; //0x44
|
||||||
|
unsigned int ofs_table_end;
|
||||||
|
|
||||||
|
//regarding the various unknowns, we can expect editor locale+usage (which are useless to us), blendfunc+alphafunc++cullface+depthtest+depthwrite+polygonoffset, maybe some tessellation settings and envmapping stuff.
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int ofs_sampler;
|
||||||
|
unsigned int flags; //maybe? 0x200 for rgb, 0x300 for normals, 0x400 for spec...? there's probably clamping options here.
|
||||||
|
//&7==0: default
|
||||||
|
//&7==1: nearest... or trilinear?!?
|
||||||
|
//&7==2: linear
|
||||||
|
//&7==3: ???
|
||||||
|
//&7==4: ???
|
||||||
|
//&7==5: ???
|
||||||
|
//&7==6: bilinear
|
||||||
|
//&7==7: anisotropic
|
||||||
|
unsigned int ofs_texname;
|
||||||
|
} maps[1];
|
||||||
|
} *header = (void*)base;
|
||||||
|
unsigned int m;
|
||||||
|
if (!base)
|
||||||
|
return false; //nope, bad filename
|
||||||
|
if (header->ofs_table == 0x44) //make sure we know what it is...
|
||||||
|
{
|
||||||
|
size_t ofs = 0;
|
||||||
|
char shad[8192];
|
||||||
|
const char *srcfac, *dstfac;
|
||||||
|
|
||||||
|
//no initial { cos we're weird.
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\n"),ofs+=strlen(shad+ofs); //not actually useful to us. maybe for the hud so it doesn't have to wait for the image data too?
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\t//material='%s'\n\t//tooltex='%s'\n", base+header->ofs_materialname, base+header->ofs_texturename),ofs+=strlen(shad+ofs);
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\t//z1=%#x z2=%#x z3=%#x\n\t//unk1=%#x,%#x,%#x,%#x\n\t//unk2=%#x,%#x\n\t//unk3=%#x\n\t//surfaceflags=%#x\n\t//contentbits=%#x\n\t//unk6=%#x\n\t//unk7=%#x\n\t//unk8=%#x\n", header->z1, header->z2, header->z3, header->unk10,header->sort,header->unk12,header->unk13, header->unk2[0],header->unk2[1], header->unk3, header->surfaceflags, header->contentbits, header->blendbits, header->unk7, header->unk8),ofs+=strlen(shad+ofs);
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\timagesize %i %i\n", header->width, header->height),ofs+=strlen(shad+ofs); //not actually useful to us. maybe for the hud so it doesn't have to wait for the image data too?
|
||||||
|
|
||||||
|
for (m = 0; m < (header->ofs_table_end-header->ofs_table)/sizeof(header->maps[0]); m++)
|
||||||
|
{
|
||||||
|
const char *sampler = base+header->maps[m].ofs_sampler;
|
||||||
|
if (!strcmp(sampler, "colorMap"))
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\tdiffusemap images/%s.iwi //%#x\n", base+header->maps[m].ofs_texname, header->maps[m].flags),ofs+=strlen(shad+ofs);
|
||||||
|
else if (!strcmp(sampler, "normalMap"))
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\tnormalmap images/%s.iwi //%#x\n", base+header->maps[m].ofs_texname, header->maps[m].flags),ofs+=strlen(shad+ofs);
|
||||||
|
else if (!strcmp(sampler, "detailMap"))
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\tdisplacementmap images/%s.iwi //%#x\n", base+header->maps[m].ofs_texname, header->maps[m].flags),ofs+=strlen(shad+ofs); //hack. might as well use this one as detail.
|
||||||
|
else if (!strcmp(sampler, "specularMap"))
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\tspecularmap images/%s.iwi //%#x\n", base+header->maps[m].ofs_texname, header->maps[m].flags),ofs+=strlen(shad+ofs);
|
||||||
|
else
|
||||||
|
Con_Printf("\t%s:%#x<-%s\n", base+header->maps[m].ofs_sampler, header->maps[m].flags, base+header->maps[m].ofs_texname);
|
||||||
|
}
|
||||||
|
|
||||||
|
//spit out a pass...
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\t{\n"),ofs+=strlen(shad+ofs);
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\t\tprogram %s\n", base+header->ofs_program),ofs+=strlen(shad+ofs);
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\t\tmap $diffuse\n"),ofs+=strlen(shad+ofs); //just in case.
|
||||||
|
|
||||||
|
switch((header->blendbits>>0)&0xf)
|
||||||
|
{ //source factors
|
||||||
|
default:
|
||||||
|
case 1: srcfac="zero"; break;
|
||||||
|
case 2: srcfac="one"; break;
|
||||||
|
case 3: srcfac="src_color"; break;
|
||||||
|
case 4: srcfac="one_minus_src_color"; break;
|
||||||
|
case 5: srcfac="src_alpha"; break;
|
||||||
|
case 6: srcfac="one_minus_src_alpha"; break;
|
||||||
|
case 7: srcfac="dst_alpha"; break;
|
||||||
|
case 8: srcfac="one_minus_dst_alpha"; break;
|
||||||
|
case 9: srcfac="dst_color"; break;
|
||||||
|
case 10: srcfac="one_minus_dst_color"; break;
|
||||||
|
case 11: srcfac="src_alpha_sat"; break;
|
||||||
|
case 12: srcfac="both_src_alpha"; break;
|
||||||
|
case 13: srcfac="both_one_minus_src_alpha"; break;
|
||||||
|
case 14: srcfac="blend_factor"; break;
|
||||||
|
case 15: srcfac="one_minus_blend_factor"; break;
|
||||||
|
}
|
||||||
|
switch((header->blendbits>>4)&0xf)
|
||||||
|
{ //dest factors
|
||||||
|
default:
|
||||||
|
case 1: dstfac="zero"; break;
|
||||||
|
case 2: dstfac="one"; break;
|
||||||
|
case 3: dstfac="src_color"; break;
|
||||||
|
case 4: dstfac="one_minus_src_color"; break;
|
||||||
|
case 5: dstfac="src_alpha"; break;
|
||||||
|
case 6: dstfac="one_minus_src_alpha"; break;
|
||||||
|
case 7: dstfac="dst_alpha"; break;
|
||||||
|
case 8: dstfac="one_minus_dst_alpha"; break;
|
||||||
|
case 9: dstfac="dst_color"; break;
|
||||||
|
case 10: dstfac="one_minus_dst_color"; break;
|
||||||
|
case 11: dstfac="src_alpha_sat"; break;
|
||||||
|
case 12: dstfac="both_src_alpha"; break;
|
||||||
|
case 13: dstfac="both_one_minus_src_alpha"; break;
|
||||||
|
case 14: dstfac="blend_factor"; break;
|
||||||
|
case 15: dstfac="one_minus_blend_factor"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\t\tblendfunc %s %s\n", srcfac, dstfac),ofs+=strlen(shad+ofs); //just in case.
|
||||||
|
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "\t}\n"),ofs+=strlen(shad+ofs);
|
||||||
|
|
||||||
|
Q_snprintf(shad+ofs,sizeof(shad)-ofs, "}\n");
|
||||||
|
plugfuncs->Free(base);
|
||||||
|
LoadMaterialString(ps, shad);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Con_Printf(CON_WARNING"%s doesn't seem to be a material? table=%#x..%#x\n", filename, header->ofs_table, header->ofs_table_end);
|
||||||
|
plugfuncs->Free(base);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean SType_LoadShader(parsestate_t *ps, const char *filename, void (*LoadMaterialString)(parsestate_t *ps, const char *script))
|
||||||
|
{
|
||||||
|
char stypefname[MAX_QPATH];
|
||||||
|
char *path;
|
||||||
|
const char *sep;
|
||||||
|
const char *at;
|
||||||
|
size_t pre;
|
||||||
|
char *base, *in, *out;
|
||||||
|
|
||||||
|
sep = strrchr(filename, '/');
|
||||||
|
if (!sep++)
|
||||||
|
return COD2_DecodeMaterial(ps, filename, LoadMaterialString);
|
||||||
|
at = strrchr(sep, '@');
|
||||||
|
if (!at)
|
||||||
|
return false; //nope, no shadertype specified. depend on the engine/loader/etc defaults.
|
||||||
|
|
||||||
|
if (!strncmp(filename, "skins/", 5))
|
||||||
|
path = "shadertypes/model/";
|
||||||
|
else if (!strncmp(filename, "textures/", 9))
|
||||||
|
path = "shadertypes/world/";
|
||||||
|
else if (!strncmp(filename, "gfx/", 4))
|
||||||
|
path = "shadertypes/2d/";
|
||||||
|
else
|
||||||
|
return false; //nope, not gonna try.
|
||||||
|
|
||||||
|
pre = strlen(path);
|
||||||
|
if (pre+(at-sep)+7 > sizeof(stypefname))
|
||||||
|
return false; //nope, too long...
|
||||||
|
memcpy(stypefname, path, pre);
|
||||||
|
memcpy(stypefname+pre, sep, at-sep);
|
||||||
|
memcpy(stypefname+pre+(at-sep), ".stype", 7);
|
||||||
|
|
||||||
|
in = out = base = fsfuncs->LoadFile(stypefname, &pre);
|
||||||
|
if (!base)
|
||||||
|
return false; //nope, bad filename
|
||||||
|
//yay we got something, but we need to fix up the $texturename strings to $diffuse because $reasons
|
||||||
|
while (*in)
|
||||||
|
{
|
||||||
|
if (*in == '$' && !strncmp(in, "$texturename", 12))
|
||||||
|
{
|
||||||
|
memcpy(out, "$diffuse", 8);
|
||||||
|
out += 8;
|
||||||
|
in += 12;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*out++ = *in++;
|
||||||
|
}
|
||||||
|
*out = 0;
|
||||||
|
|
||||||
|
//now hand over the fteised shader script.
|
||||||
|
in = base;
|
||||||
|
while(*in == ' ' || *in == '\t' || *in == '\n' || *in == '\r')
|
||||||
|
in++;
|
||||||
|
if (*in == '{')
|
||||||
|
in++;
|
||||||
|
LoadMaterialString(ps, in);
|
||||||
|
plugfuncs->Free(base); //done with it now.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static struct sbuiltin_s codprograms[] =
|
||||||
|
{
|
||||||
|
{QR_NONE}
|
||||||
|
};*/
|
||||||
|
static plugmaterialloaderfuncs_t stypefuncs =
|
||||||
|
{
|
||||||
|
"Cod Shader Types",
|
||||||
|
SType_LoadShader,
|
||||||
|
|
||||||
|
// codprograms,
|
||||||
|
};
|
||||||
|
qboolean STypes_Init(void)
|
||||||
|
{
|
||||||
|
fsfuncs = plugfuncs->GetEngineInterface(plugfsfuncs_name, sizeof(*fsfuncs));
|
||||||
|
if (!fsfuncs)
|
||||||
|
return false;
|
||||||
|
return plugfuncs->ExportInterface(plugmaterialloaderfuncs_name, &stypefuncs, sizeof(stypefuncs));
|
||||||
|
}
|
955
plugins/cod/codmod.c
Normal file
955
plugins/cod/codmod.c
Normal file
|
@ -0,0 +1,955 @@
|
||||||
|
#include "../plugin.h"
|
||||||
|
#include "../engine/common/com_mesh.h"
|
||||||
|
static plugfsfuncs_t *filefuncs;
|
||||||
|
static plugmodfuncs_t *modfuncs;
|
||||||
|
|
||||||
|
//Utility functions. silly plugins.
|
||||||
|
float Length(const vec3_t v) {return sqrt(DotProduct(v,v));}
|
||||||
|
float RadiusFromBounds (const vec3_t mins, const vec3_t maxs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vec3_t corner;
|
||||||
|
for (i=0 ; i<3 ; i++)
|
||||||
|
corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);
|
||||||
|
return Length(corner);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct fstream_s
|
||||||
|
{
|
||||||
|
void *start;
|
||||||
|
size_t len;
|
||||||
|
size_t ofs;
|
||||||
|
|
||||||
|
size_t numbones;
|
||||||
|
galiasbone_t *bones;
|
||||||
|
float *basepose;
|
||||||
|
};
|
||||||
|
struct lod_s
|
||||||
|
{
|
||||||
|
float coverage;
|
||||||
|
const char *name;
|
||||||
|
unsigned short numtex;
|
||||||
|
const char *tex[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
static qboolean ReadEOF(struct fstream_s *f)
|
||||||
|
{
|
||||||
|
return (f->ofs >= f->len);
|
||||||
|
}
|
||||||
|
static qbyte ReadByte(struct fstream_s *f)
|
||||||
|
{
|
||||||
|
if (f->ofs+1 > f->len)
|
||||||
|
{
|
||||||
|
f->ofs++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ((qbyte*)f->start)[f->ofs++];
|
||||||
|
}
|
||||||
|
static const char *ReadBytes(struct fstream_s *f, size_t len)
|
||||||
|
{
|
||||||
|
f->ofs+=len;
|
||||||
|
if (f->ofs > f->len)
|
||||||
|
return NULL;
|
||||||
|
return &((const char*)f->start)[f->ofs-len];
|
||||||
|
}
|
||||||
|
static const char *ReadString(struct fstream_s *f)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
for (len = 0; f->ofs+len < f->len && ((qbyte*)f->start)[f->ofs+len]; len++)
|
||||||
|
;
|
||||||
|
len++; //for the null
|
||||||
|
f->ofs += len;
|
||||||
|
return &((const qbyte*)f->start)[f->ofs-len];
|
||||||
|
}
|
||||||
|
static unsigned short ReadUInt16(struct fstream_s *f)
|
||||||
|
{
|
||||||
|
unsigned short r;
|
||||||
|
r = ReadByte(f);
|
||||||
|
r|= ReadByte(f) << 8;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
static short ReadSInt16(struct fstream_s *f)
|
||||||
|
{
|
||||||
|
return (signed short)ReadUInt16(f);
|
||||||
|
}
|
||||||
|
static unsigned int ReadUInt32(struct fstream_s *f)
|
||||||
|
{
|
||||||
|
unsigned int r;
|
||||||
|
r = ReadByte(f);
|
||||||
|
r|= ReadByte(f) << 8;
|
||||||
|
r|= ReadByte(f) << 16;
|
||||||
|
r|= ReadByte(f) << 24;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
static float ReadFloat(struct fstream_s *f)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
unsigned int u;
|
||||||
|
float f;
|
||||||
|
} r;
|
||||||
|
r.u = ReadByte(f);
|
||||||
|
r.u|= ReadByte(f) << 8;
|
||||||
|
r.u|= ReadByte(f) << 16;
|
||||||
|
r.u|= ReadByte(f) << 24;
|
||||||
|
return r.f;
|
||||||
|
}
|
||||||
|
static qboolean Mod_XModel_LoadPart (struct model_s *mod, struct fstream_s *f)
|
||||||
|
{
|
||||||
|
unsigned short ver = ReadUInt16(f);
|
||||||
|
unsigned short b, nboner = ReadUInt16(f);
|
||||||
|
unsigned short nbonea = ReadUInt16(f);
|
||||||
|
float rel[12];
|
||||||
|
switch(ver)
|
||||||
|
{
|
||||||
|
case 0x0e:
|
||||||
|
break;
|
||||||
|
case 0x14:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Con_Printf(CON_ERROR"%s: Unknown version %#x\n", mod->name, ver);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Con_Printf("%s: version %x rb:%i ab:%i\n", mod->name, ver, nboner, nbonea);
|
||||||
|
f->numbones = nbonea+nboner;
|
||||||
|
f->basepose = plugfuncs->GMalloc(&mod->memgroup, sizeof(*f->basepose)*12 * f->numbones);
|
||||||
|
f->bones = plugfuncs->GMalloc(&mod->memgroup, sizeof(*f->bones) * f->numbones);
|
||||||
|
|
||||||
|
for (b = 0; b < nbonea; b++)
|
||||||
|
{ //root bones, with identity position. for some reason.
|
||||||
|
f->bones[b].parent = -1;
|
||||||
|
|
||||||
|
VectorClear(f->bones[b].ref.org);
|
||||||
|
Vector4Set(f->bones[b].ref.quat, 0, 0, 0, 1);
|
||||||
|
VectorSet(f->bones[b].ref.scale, 1, 1, 1);
|
||||||
|
modfuncs->GenMatrixPosQuat4Scale(f->bones[b].ref.org, f->bones[b].ref.quat, f->bones[b].ref.scale, f->basepose + b*12);
|
||||||
|
}
|
||||||
|
for (; b < f->numbones; b++)
|
||||||
|
{
|
||||||
|
f->bones[b].parent = ReadByte(f);
|
||||||
|
|
||||||
|
if (f->bones[b].parent >= b)
|
||||||
|
Con_Printf(CON_ERROR"b%i (%s) has parent %i\n", b, f->bones[b].name, f->bones[b].parent);
|
||||||
|
|
||||||
|
f->bones[b].ref.org[0] = ReadFloat(f);
|
||||||
|
f->bones[b].ref.org[1] = ReadFloat(f);
|
||||||
|
f->bones[b].ref.org[2] = ReadFloat(f);
|
||||||
|
|
||||||
|
f->bones[b].ref.quat[0] = ReadSInt16(f)/32767.0f;
|
||||||
|
f->bones[b].ref.quat[1] = ReadSInt16(f)/32767.0f;
|
||||||
|
f->bones[b].ref.quat[2] = ReadSInt16(f)/32767.0f;
|
||||||
|
f->bones[b].ref.quat[3] = 1.0-DotProduct(f->bones[b].ref.quat,f->bones[b].ref.quat); //reconstruct the w part.
|
||||||
|
if (f->bones[b].ref.quat[3]>0)
|
||||||
|
f->bones[b].ref.quat[3] = sqrt(f->bones[b].ref.quat[3]);
|
||||||
|
else
|
||||||
|
f->bones[b].ref.quat[3] = 0;
|
||||||
|
|
||||||
|
VectorSet(f->bones[b].ref.scale, 1, 1, 1);
|
||||||
|
|
||||||
|
modfuncs->GenMatrixPosQuat4Scale(f->bones[b].ref.org, f->bones[b].ref.quat, f->bones[b].ref.scale, rel);
|
||||||
|
modfuncs->ConcatTransforms((void*)(f->basepose + f->bones[b].parent*12), (void*)rel, (void*)(f->basepose + b*12));
|
||||||
|
|
||||||
|
// Con_Printf("b%i: p:%i, [%f %f %f] [%f %f %f %f]\n", b, f->bones[b].parent, pos[0],pos[1],pos[2], quat[0],quat[1],quat[2],quat[3]);
|
||||||
|
}
|
||||||
|
for (b = 0; b < f->numbones; b++)
|
||||||
|
{
|
||||||
|
vec3_t mins, maxs;
|
||||||
|
const char *n = ReadString(f);
|
||||||
|
if (ver >= 0x14)
|
||||||
|
{ //omitted.
|
||||||
|
VectorClear(mins);
|
||||||
|
VectorClear(maxs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mins[0] = ReadFloat(f);
|
||||||
|
mins[1] = ReadFloat(f);
|
||||||
|
mins[2] = ReadFloat(f);
|
||||||
|
maxs[0] = ReadFloat(f);
|
||||||
|
maxs[1] = ReadFloat(f);
|
||||||
|
maxs[2] = ReadFloat(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//hack... I assume the (game)code does a skel_setbone so this doesn't actually matter?
|
||||||
|
if (!strcmp(n, "torso_stabilizer"))
|
||||||
|
Vector4Set(f->bones[b].ref.quat, 0,0,0,1);
|
||||||
|
|
||||||
|
Q_strlcpy(f->bones[b].name, n, sizeof(f->bones[b].name));
|
||||||
|
modfuncs->M3x4_Invert(f->basepose+12*b, f->bones[b].inverse);
|
||||||
|
|
||||||
|
// if (ver >= 0x14)
|
||||||
|
// Con_Printf("b%i: %-20s\n", b, n);
|
||||||
|
// else
|
||||||
|
// Con_Printf("b%i: %-20s [%f %f %f] [%f %f %f]\n", b, n, mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]);
|
||||||
|
}
|
||||||
|
for (b = 0; b < f->numbones; b++)
|
||||||
|
f->bones[b].group = ReadByte(f); //presumed.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static qboolean Mod_XModel_LoadSurfs (struct model_s *mod, struct fstream_s *f, struct lod_s *lod, float mincov)
|
||||||
|
{
|
||||||
|
galiasinfo_t *surf;
|
||||||
|
galiasskin_t *skins;
|
||||||
|
skinframe_t *skinframe;
|
||||||
|
unsigned short ver = ReadUInt16(f);
|
||||||
|
unsigned short n, nsurfs = ReadUInt16(f);
|
||||||
|
switch(ver)
|
||||||
|
{
|
||||||
|
case 0x0e:
|
||||||
|
break;
|
||||||
|
case 0x14:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Con_Printf("%s: Unknown version %#x\n", mod->name, ver);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nsurfs)
|
||||||
|
return true; //nothing to do...
|
||||||
|
|
||||||
|
surf = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf)*nsurfs +
|
||||||
|
sizeof(*skins)*nsurfs +
|
||||||
|
sizeof(*skinframe)*nsurfs);
|
||||||
|
skins = (galiasskin_t*)(surf+nsurfs);
|
||||||
|
skinframe = (skinframe_t*)(skins+nsurfs);
|
||||||
|
for (n = 0; n < nsurfs; n++)
|
||||||
|
{
|
||||||
|
surf[n].numbones = f->numbones;
|
||||||
|
surf[n].ofsbones = f->bones;
|
||||||
|
surf[n].baseframeofs = f->basepose;
|
||||||
|
|
||||||
|
surf[n].mindist = mincov;
|
||||||
|
surf[n].maxdist = lod->coverage;
|
||||||
|
surf[n].shares_verts = n;
|
||||||
|
surf[n].shares_bones = 0;
|
||||||
|
surf[n].nextsurf = &surf[n+1];
|
||||||
|
surf[n].ofsskins = &skins[n];
|
||||||
|
surf[n].numskins = 1;
|
||||||
|
skins[n].skinspeed = 0.1;
|
||||||
|
skins[n].frame = &skinframe[n];
|
||||||
|
skins[n].numframes = 1;
|
||||||
|
Q_snprintf(surf[n].surfacename, sizeof(surf[n].surfacename), "%s/%i", lod->name, n);
|
||||||
|
Q_strlcpy(skins[n].name, lod->name, sizeof(skins[n].name));
|
||||||
|
if (n < lod->numtex)
|
||||||
|
Q_snprintf(skinframe[n].shadername, sizeof(skinframe[n].shadername), (ver==0x0e)?"skins/%s":"%s", lod->tex[n]);
|
||||||
|
}
|
||||||
|
surf[nsurfs-1].nextsurf = mod->meshinfo;
|
||||||
|
mod->meshinfo = surf;
|
||||||
|
for(surf = surf[nsurfs-1].nextsurf; surf; surf = surf->nextsurf)
|
||||||
|
surf->shares_verts += nsurfs;
|
||||||
|
surf = mod->meshinfo;
|
||||||
|
|
||||||
|
for (n = 0; n < nsurfs; n++, surf++)
|
||||||
|
{
|
||||||
|
int flags = ReadByte(f);
|
||||||
|
int v, nverts = ReadUInt16(f);
|
||||||
|
int t, ntris = ReadUInt16(f);
|
||||||
|
int r, runs = (ver==0xe)?ReadUInt16(f):0;
|
||||||
|
unsigned short wcount = 0;
|
||||||
|
qbyte run;
|
||||||
|
unsigned int idx1, idx2, idx3;
|
||||||
|
|
||||||
|
unsigned short boneidx = ReadUInt16(f);
|
||||||
|
qboolean boney = boneidx == (unsigned short)~0u;
|
||||||
|
int exweights = 0;
|
||||||
|
unsigned short *vw = NULL;
|
||||||
|
// unsigned short bunk2;
|
||||||
|
|
||||||
|
vec3_t norm;
|
||||||
|
vec4_t xyzw;
|
||||||
|
const float *matrix;
|
||||||
|
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
|
if (boney)
|
||||||
|
{
|
||||||
|
if (ver == 0x0e)
|
||||||
|
exweights = ReadUInt16(f);
|
||||||
|
/*bunk2 =*/ ReadUInt16(f); //seems to be vaguely related to vert/triangle counts.
|
||||||
|
}
|
||||||
|
|
||||||
|
surf->numverts = nverts;
|
||||||
|
|
||||||
|
if (ver == 0xe)
|
||||||
|
{ //cod1
|
||||||
|
surf->ofs_indexes = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_indexes ) * ntris*3);
|
||||||
|
for(t = 0, r = 0; r < runs; r++)
|
||||||
|
{
|
||||||
|
run = ReadByte(f);
|
||||||
|
idx1 = ReadUInt16(f);
|
||||||
|
idx2 = ReadUInt16(f);
|
||||||
|
run-=2;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{ //strip
|
||||||
|
if(!run--) break;
|
||||||
|
idx3 = ReadUInt16(f);
|
||||||
|
if (idx1 != idx2 && idx1 != idx3 && idx2 != idx3 && t < ntris)
|
||||||
|
{
|
||||||
|
surf->ofs_indexes[t*3+0] = idx1;
|
||||||
|
surf->ofs_indexes[t*3+1] = idx2;
|
||||||
|
surf->ofs_indexes[t*3+2] = idx3;
|
||||||
|
t++;
|
||||||
|
}
|
||||||
|
idx1 = idx2;
|
||||||
|
idx2 = idx3;
|
||||||
|
|
||||||
|
//alternating triangles flip the order
|
||||||
|
if(!run--) break;
|
||||||
|
idx3 = ReadUInt16(f);
|
||||||
|
if (idx1 != idx2 && idx1 != idx3 && idx2 != idx3 && t < ntris)
|
||||||
|
{
|
||||||
|
surf->ofs_indexes[t*3+2] = idx1;
|
||||||
|
surf->ofs_indexes[t*3+1] = idx2;
|
||||||
|
surf->ofs_indexes[t*3+0] = idx3;
|
||||||
|
t++;
|
||||||
|
}
|
||||||
|
idx1 = idx2;
|
||||||
|
idx2 = idx3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ntris != t)
|
||||||
|
{
|
||||||
|
Con_Printf(CON_ERROR"Expected %i tris, got %i from %i runs\n", ntris, t, r);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
surf->numindexes = t*3;
|
||||||
|
|
||||||
|
//lazy and a bit slower.
|
||||||
|
surf->ofs_st_array = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_st_array ) * surf->numverts);
|
||||||
|
surf->ofs_skel_xyz = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_xyz ) * surf->numverts);
|
||||||
|
surf->ofs_skel_norm = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_norm ) * surf->numverts);
|
||||||
|
if (boney || f->numbones>0)
|
||||||
|
{
|
||||||
|
surf->ofs_skel_idx = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_idx ) * surf->numverts);
|
||||||
|
surf->ofs_skel_weight = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_weight ) * surf->numverts);
|
||||||
|
vw = memset(alloca(sizeof(*vw)*nverts), 0, sizeof(*vw)*nverts);
|
||||||
|
}
|
||||||
|
boneidx = min(boneidx,f->numbones-1);
|
||||||
|
|
||||||
|
for (v = 0; v < nverts; v++)
|
||||||
|
{
|
||||||
|
norm[0] = ReadFloat(f);
|
||||||
|
norm[1] = ReadFloat(f);
|
||||||
|
norm[2] = ReadFloat(f);
|
||||||
|
surf->ofs_st_array[v][0] = ReadFloat(f);
|
||||||
|
surf->ofs_st_array[v][1] = ReadFloat(f);
|
||||||
|
if (boney)
|
||||||
|
{
|
||||||
|
wcount = ReadUInt16(f);
|
||||||
|
boneidx = ReadUInt16(f);
|
||||||
|
boneidx = min(boneidx,f->numbones-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
xyzw[0] = ReadFloat(f);
|
||||||
|
xyzw[1] = ReadFloat(f);
|
||||||
|
xyzw[2] = ReadFloat(f);
|
||||||
|
if (wcount)
|
||||||
|
{
|
||||||
|
xyzw[3] = ReadFloat(f);
|
||||||
|
VectorScale(xyzw, xyzw[3], xyzw);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
xyzw[3] = 1;
|
||||||
|
|
||||||
|
if (surf->ofs_skel_idx)
|
||||||
|
{
|
||||||
|
vw[v] = wcount; //urgh.
|
||||||
|
surf->ofs_skel_idx[v][0] = surf->ofs_skel_idx[v][1] = surf->ofs_skel_idx[v][2] = surf->ofs_skel_idx[v][3] = boneidx; //set all of them, cache might thank us.
|
||||||
|
surf->ofs_skel_weight[v][0] = xyzw[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
//calculate the correct position in the base pose
|
||||||
|
matrix = f->basepose + boneidx*12;
|
||||||
|
surf->ofs_skel_xyz[ v][0] = xyzw[0] * matrix[0] + xyzw[1] * matrix[1] + xyzw[2] * matrix[ 2] + xyzw[3] * matrix[ 3];
|
||||||
|
surf->ofs_skel_xyz[ v][1] = xyzw[0] * matrix[4] + xyzw[1] * matrix[5] + xyzw[2] * matrix[ 6] + xyzw[3] * matrix[ 7];
|
||||||
|
surf->ofs_skel_xyz[ v][2] = xyzw[0] * matrix[8] + xyzw[1] * matrix[9] + xyzw[2] * matrix[10] + xyzw[3] * matrix[11];
|
||||||
|
surf->ofs_skel_norm[v][0] = norm[0] * matrix[0] + norm[1] * matrix[1] + norm[2] * matrix[ 2];
|
||||||
|
surf->ofs_skel_norm[v][1] = norm[0] * matrix[4] + norm[1] * matrix[5] + norm[2] * matrix[ 6];
|
||||||
|
surf->ofs_skel_norm[v][2] = norm[0] * matrix[8] + norm[1] * matrix[9] + norm[2] * matrix[10];
|
||||||
|
}
|
||||||
|
if (vw)
|
||||||
|
{
|
||||||
|
float lowestv;
|
||||||
|
int lowesti, j;
|
||||||
|
for (v = 0; v < nverts; v++)
|
||||||
|
{
|
||||||
|
for (; vw[v] > 0; vw[v]--)
|
||||||
|
{
|
||||||
|
if (--exweights < 0)
|
||||||
|
break;
|
||||||
|
boneidx = ReadUInt16(f);
|
||||||
|
boneidx = min(boneidx,f->numbones-1);
|
||||||
|
xyzw[0] = ReadFloat(f);
|
||||||
|
xyzw[1] = ReadFloat(f);
|
||||||
|
xyzw[2] = ReadFloat(f);
|
||||||
|
xyzw[3] = ReadFloat(f);
|
||||||
|
VectorScale(xyzw, xyzw[3], xyzw);
|
||||||
|
|
||||||
|
matrix = f->basepose + boneidx*12;
|
||||||
|
surf->ofs_skel_xyz[ v][0] += xyzw[0] * matrix[0] + xyzw[1] * matrix[1] + xyzw[2] * matrix[ 2] + xyzw[3] * matrix[ 3];
|
||||||
|
surf->ofs_skel_xyz[ v][1] += xyzw[0] * matrix[4] + xyzw[1] * matrix[5] + xyzw[2] * matrix[ 6] + xyzw[3] * matrix[ 7];
|
||||||
|
surf->ofs_skel_xyz[ v][2] += xyzw[0] * matrix[8] + xyzw[1] * matrix[9] + xyzw[2] * matrix[10] + xyzw[3] * matrix[11];
|
||||||
|
|
||||||
|
lowesti = 0;
|
||||||
|
lowestv = surf->ofs_skel_weight[v][0];
|
||||||
|
for (j = 1; j < countof(surf->ofs_skel_idx[v]); j++)
|
||||||
|
{
|
||||||
|
if (surf->ofs_skel_weight[v][j] < lowestv)
|
||||||
|
lowestv = surf->ofs_skel_weight[v][lowesti=j];
|
||||||
|
}
|
||||||
|
if (lowestv < xyzw[3])
|
||||||
|
{
|
||||||
|
surf->ofs_skel_idx[v][lowesti] = boneidx;
|
||||||
|
surf->ofs_skel_weight[v][lowesti] = xyzw[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//compensate for any missing weights
|
||||||
|
xyzw[3] = surf->ofs_skel_weight[v][0]+surf->ofs_skel_weight[v][1]+surf->ofs_skel_weight[v][2]+surf->ofs_skel_weight[v][3];
|
||||||
|
if (xyzw[3]>0)
|
||||||
|
Vector4Scale(surf->ofs_skel_weight[v], 1/xyzw[3], surf->ofs_skel_weight[v]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exweights)
|
||||||
|
{ //something was misread
|
||||||
|
surf->numverts = 0;
|
||||||
|
surf->numindexes = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//compute the tangents that are not stored in the file.
|
||||||
|
surf->ofs_skel_svect = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_svect ) * surf->numverts);
|
||||||
|
surf->ofs_skel_tvect = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_tvect ) * surf->numverts);
|
||||||
|
modfuncs->AccumulateTextureVectors(surf->ofs_skel_xyz, surf->ofs_st_array, surf->ofs_skel_norm, surf->ofs_skel_svect, surf->ofs_skel_tvect, surf->ofs_indexes, surf->numindexes, false);
|
||||||
|
modfuncs->NormaliseTextureVectors(surf->ofs_skel_norm, surf->ofs_skel_svect, surf->ofs_skel_tvect, surf->numverts, false);
|
||||||
|
}
|
||||||
|
else if (ver == 0x14)
|
||||||
|
{ //cod2
|
||||||
|
surf->ofs_st_array = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_st_array ) * surf->numverts);
|
||||||
|
surf->ofs_skel_xyz = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_xyz ) * surf->numverts);
|
||||||
|
surf->ofs_skel_norm = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_norm ) * surf->numverts);
|
||||||
|
surf->ofs_skel_svect = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_svect ) * surf->numverts);
|
||||||
|
surf->ofs_skel_tvect = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_tvect ) * surf->numverts);
|
||||||
|
surf->ofs_rgbaub = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_rgbaub ) * surf->numverts);
|
||||||
|
|
||||||
|
if (boney || f->numbones)
|
||||||
|
{
|
||||||
|
surf->ofs_skel_idx = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_idx ) * surf->numverts);
|
||||||
|
surf->ofs_skel_weight = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_skel_weight ) * surf->numverts);
|
||||||
|
}
|
||||||
|
boneidx = min(boneidx,f->numbones-1);
|
||||||
|
|
||||||
|
for (v = 0; v < nverts; v++)
|
||||||
|
{
|
||||||
|
surf->ofs_skel_norm[v][0] = ReadFloat(f);
|
||||||
|
surf->ofs_skel_norm[v][1] = ReadFloat(f);
|
||||||
|
surf->ofs_skel_norm[v][2] = ReadFloat(f);
|
||||||
|
surf->ofs_rgbaub[v][0] = ReadByte(f);
|
||||||
|
surf->ofs_rgbaub[v][1] = ReadByte(f);
|
||||||
|
surf->ofs_rgbaub[v][2] = ReadByte(f);
|
||||||
|
surf->ofs_rgbaub[v][3] = ReadByte(f);
|
||||||
|
surf->ofs_st_array[v][0] = ReadFloat(f);
|
||||||
|
surf->ofs_st_array[v][1] = ReadFloat(f);
|
||||||
|
surf->ofs_skel_svect[v][0] = ReadFloat(f);
|
||||||
|
surf->ofs_skel_svect[v][1] = ReadFloat(f);
|
||||||
|
surf->ofs_skel_svect[v][2] = ReadFloat(f);
|
||||||
|
surf->ofs_skel_tvect[v][0] = ReadFloat(f);
|
||||||
|
surf->ofs_skel_tvect[v][1] = ReadFloat(f);
|
||||||
|
surf->ofs_skel_tvect[v][2] = ReadFloat(f);
|
||||||
|
if (boney)
|
||||||
|
{
|
||||||
|
int w;
|
||||||
|
wcount = ReadByte(f);
|
||||||
|
boneidx = ReadUInt16(f);
|
||||||
|
boneidx = min(boneidx,f->numbones-1);
|
||||||
|
xyzw[0] = ReadFloat(f);
|
||||||
|
xyzw[1] = ReadFloat(f);
|
||||||
|
xyzw[2] = ReadFloat(f);
|
||||||
|
xyzw[3] = wcount?ReadByte(f)/255.f:1;
|
||||||
|
VectorScale(xyzw, xyzw[3], xyzw);
|
||||||
|
matrix = f->basepose + boneidx*12;
|
||||||
|
surf->ofs_skel_xyz[ v][0] = xyzw[0] * matrix[0] + xyzw[1] * matrix[1] + xyzw[2] * matrix[ 2] + xyzw[3] * matrix[ 3];
|
||||||
|
surf->ofs_skel_xyz[ v][1] = xyzw[0] * matrix[4] + xyzw[1] * matrix[5] + xyzw[2] * matrix[ 6] + xyzw[3] * matrix[ 7];
|
||||||
|
surf->ofs_skel_xyz[ v][2] = xyzw[0] * matrix[8] + xyzw[1] * matrix[9] + xyzw[2] * matrix[10] + xyzw[3] * matrix[11];
|
||||||
|
|
||||||
|
surf->ofs_skel_idx[v][0] = surf->ofs_skel_idx[v][1] = surf->ofs_skel_idx[v][2] = surf->ofs_skel_idx[v][3] = boneidx;
|
||||||
|
surf->ofs_skel_weight[v][0] = xyzw[3]; surf->ofs_skel_weight[v][1] = surf->ofs_skel_weight[v][2] = surf->ofs_skel_weight[v][3] = 0;
|
||||||
|
|
||||||
|
for (w = 1; w <= wcount; w++)
|
||||||
|
{
|
||||||
|
boneidx = ReadUInt16(f);
|
||||||
|
boneidx = min(boneidx,f->numbones-1);
|
||||||
|
xyzw[0] = ReadFloat(f);
|
||||||
|
xyzw[1] = ReadFloat(f);
|
||||||
|
xyzw[2] = ReadFloat(f);
|
||||||
|
xyzw[3] = ReadUInt16(f)/65535.f;
|
||||||
|
VectorScale(xyzw, xyzw[3], xyzw);
|
||||||
|
matrix = f->basepose + boneidx*12;
|
||||||
|
surf->ofs_skel_xyz[ v][0] += xyzw[0] * matrix[0] + xyzw[1] * matrix[1] + xyzw[2] * matrix[ 2] + xyzw[3] * matrix[ 3];
|
||||||
|
surf->ofs_skel_xyz[ v][1] += xyzw[0] * matrix[4] + xyzw[1] * matrix[5] + xyzw[2] * matrix[ 6] + xyzw[3] * matrix[ 7];
|
||||||
|
surf->ofs_skel_xyz[ v][2] += xyzw[0] * matrix[8] + xyzw[1] * matrix[9] + xyzw[2] * matrix[10] + xyzw[3] * matrix[11];
|
||||||
|
if (w < 4)
|
||||||
|
{
|
||||||
|
surf->ofs_skel_idx[v][w] = boneidx;
|
||||||
|
surf->ofs_skel_weight[v][w] = xyzw[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//compensate for any missing weights
|
||||||
|
xyzw[3] = surf->ofs_skel_weight[v][0]+surf->ofs_skel_weight[v][1]+surf->ofs_skel_weight[v][2]+surf->ofs_skel_weight[v][3];
|
||||||
|
if (xyzw[3]>0&&xyzw[3]!=1)
|
||||||
|
Vector4Scale(surf->ofs_skel_weight[v], 1/xyzw[3], surf->ofs_skel_weight[v]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
surf->ofs_skel_xyz[v][0] = ReadFloat(f);
|
||||||
|
surf->ofs_skel_xyz[v][1] = ReadFloat(f);
|
||||||
|
surf->ofs_skel_xyz[v][2] = ReadFloat(f);
|
||||||
|
|
||||||
|
if (surf->ofs_skel_idx)
|
||||||
|
{
|
||||||
|
surf->ofs_skel_idx[v][0] = surf->ofs_skel_idx[v][1] = surf->ofs_skel_idx[v][2] = surf->ofs_skel_idx[v][3] = boneidx;
|
||||||
|
surf->ofs_skel_weight[v][0] = 1; surf->ofs_skel_weight[v][1] = surf->ofs_skel_weight[v][2] = surf->ofs_skel_weight[v][3] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//indexes moved to AFTER. also triangles instead of weird strips. much nicer.
|
||||||
|
surf->numindexes = ntris*3;
|
||||||
|
surf->ofs_indexes = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf->ofs_indexes ) * surf->numindexes);
|
||||||
|
for (v = 0; v < ntris*3; v++)
|
||||||
|
surf->ofs_indexes[v] = ReadUInt16(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct codbone_s
|
||||||
|
{ //source data is the number of samples, the pose index for each sample and THEN the actual samples at the specified sparse poses.
|
||||||
|
// const char *name;
|
||||||
|
unsigned int numquats;
|
||||||
|
qboolean flip;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned short ts;
|
||||||
|
signed short v[3];
|
||||||
|
} *quats;
|
||||||
|
unsigned int numcoords;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int ts;
|
||||||
|
vec3_t v;
|
||||||
|
} *coord;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void Mod_XAnim_LoadQuats (struct model_s *mod, struct fstream_s *f, struct codbone_s *b, unsigned int maxts, qboolean flipquat, qboolean zonly)
|
||||||
|
{
|
||||||
|
unsigned int i, n = ReadUInt16(f);
|
||||||
|
b->flip = flipquat;
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
b->numquats = n;
|
||||||
|
b->quats = plugfuncs->GMalloc(&mod->memgroup, sizeof(*b->quats)*n);
|
||||||
|
if (n == 1 || n == maxts)
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
b->quats[i].ts = i;
|
||||||
|
else if (maxts > 0xff)
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
b->quats[i].ts = ReadUInt16(f);
|
||||||
|
else
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
b->quats[i].ts = ReadByte(f);
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
b->quats[i].v[0] = zonly?0:ReadSInt16(f);
|
||||||
|
b->quats[i].v[1] = zonly?0:ReadSInt16(f);
|
||||||
|
b->quats[i].v[2] = ReadSInt16(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void Mod_XAnim_LoadCoords (struct model_s *mod, struct fstream_s *f, struct codbone_s *b, unsigned int maxts)
|
||||||
|
{
|
||||||
|
unsigned int i, n = ReadUInt16(f);
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
b->numcoords = n;
|
||||||
|
b->coord = plugfuncs->GMalloc(&mod->memgroup, sizeof(*b->coord)*n);
|
||||||
|
if (n == 1 || n == maxts)
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
b->coord[i].ts = i;
|
||||||
|
else if (maxts > 0xff)
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
b->coord[i].ts = ReadUInt16(f);
|
||||||
|
else
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
b->coord[i].ts = ReadByte(f);
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
b->coord[i].v[0] = ReadFloat(f);
|
||||||
|
b->coord[i].v[1] = ReadFloat(f);
|
||||||
|
b->coord[i].v[2] = ReadFloat(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static float *QDECL Mod_XAnim_GetRawBones(const struct galiasinfo_s *animmesh, const struct galiasanimation_s *a, float time, float *bonematrixstorage, const struct galiasbone_s *boneinf, int numbones)
|
||||||
|
{
|
||||||
|
const struct codbone_s *bone = (const void*)(a+1);
|
||||||
|
size_t b, i, j;
|
||||||
|
int ts;
|
||||||
|
float frac;
|
||||||
|
galiasrefpose_t ref;
|
||||||
|
time *= a->rate;
|
||||||
|
ts = time;
|
||||||
|
frac = time - ts; //FIXME: negative time!
|
||||||
|
if (a->loop)
|
||||||
|
{
|
||||||
|
ts %= a->numposes;
|
||||||
|
if (ts < 0)
|
||||||
|
ts += a->numposes;
|
||||||
|
}
|
||||||
|
ts = bound(0, ts, a->numposes);
|
||||||
|
if (!boneinf)
|
||||||
|
{ //our own bones?!? that'll be a horrible mess, but if you're really asking for that...
|
||||||
|
boneinf = animmesh->ofsbones;
|
||||||
|
numbones = min(numbones,animmesh->numbones);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (b = 0; b < numbones; b++, boneinf++)
|
||||||
|
{
|
||||||
|
ref = boneinf->ref;
|
||||||
|
for (j = 0; j < animmesh->numbones; j++)
|
||||||
|
{
|
||||||
|
if (!strcmp(boneinf->name, animmesh->ofsbones[j].name))
|
||||||
|
{ //okay this is the one we want. replace the reference pose with the animated data.
|
||||||
|
bone = (const struct codbone_s*)(a+1) + j;
|
||||||
|
for (i = 0; i < bone->numquats; i++)
|
||||||
|
if (ts < bone->quats[i].ts)
|
||||||
|
break; //we flew too close to the sun!
|
||||||
|
if (!i--)
|
||||||
|
; //use the value from the model.
|
||||||
|
else if (i < bone->numquats-1 && bone->quats[i+1].ts == ts+1)
|
||||||
|
{
|
||||||
|
vec4_t oq,nq;
|
||||||
|
VectorScale(bone->quats[i].v, 1.f/32767, oq);
|
||||||
|
oq[3] = 1 - DotProduct(oq,oq);
|
||||||
|
if (oq[3] > 0)
|
||||||
|
oq[3] = sqrt(oq[3]);
|
||||||
|
|
||||||
|
VectorScale(bone->quats[i+1].v, 1.f/32767, nq);
|
||||||
|
nq[3] = 1 - DotProduct(nq,nq);
|
||||||
|
if (nq[3] > 0)
|
||||||
|
nq[3] = sqrt(nq[3]);
|
||||||
|
|
||||||
|
modfuncs->QuaternionSlerp(oq, nq, frac, ref.quat);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VectorScale(bone->quats[i].v, 1.f/32767, ref.quat);
|
||||||
|
ref.quat[3] = 1 - DotProduct(ref.quat,ref.quat);
|
||||||
|
if (ref.quat[3] > 0)
|
||||||
|
ref.quat[3] = sqrt(ref.quat[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < bone->numcoords; i++)
|
||||||
|
if (ts < bone->coord[i].ts)
|
||||||
|
break;
|
||||||
|
if (!i--)
|
||||||
|
; //use the value from the model.
|
||||||
|
else if (i < bone->numcoords-1 && bone->coord[i+1].ts == ts+1)
|
||||||
|
VectorInterpolate(bone->coord[i].v, frac, bone->coord[i+1].v, ref.org);
|
||||||
|
else
|
||||||
|
VectorCopy(bone->coord[i].v, ref.org);
|
||||||
|
|
||||||
|
break; //don't look for others.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modfuncs->GenMatrixPosQuat4Scale(ref.org, ref.quat, ref.scale, bonematrixstorage + b*12);
|
||||||
|
}
|
||||||
|
return bonematrixstorage;
|
||||||
|
}
|
||||||
|
static int Mod_XAnim_CompareEvents (const void *av, const void *bv)
|
||||||
|
{
|
||||||
|
const galiasevent_t *a=av;
|
||||||
|
const galiasevent_t *b=bv;
|
||||||
|
return b->timestamp-a->timestamp;
|
||||||
|
}
|
||||||
|
static qboolean Mod_XAnim_Load (struct model_s *mod, void *buffer, size_t fsize)
|
||||||
|
{
|
||||||
|
struct fstream_s f = {buffer, fsize};
|
||||||
|
unsigned short ver = ReadUInt16(&f);
|
||||||
|
unsigned short numposes = ReadUInt16(&f);
|
||||||
|
unsigned short numabones=0, numrbones = ReadUInt16(&f);
|
||||||
|
unsigned char flags = ReadByte(&f);
|
||||||
|
unsigned short framerate = ReadUInt16(&f);
|
||||||
|
unsigned int i;
|
||||||
|
const qbyte *flip, *tiny;
|
||||||
|
struct codbone_s *bone;
|
||||||
|
galiasinfo_t *surf;
|
||||||
|
galiasanimation_t *anim;
|
||||||
|
galiasbone_t *gbones;
|
||||||
|
int numev;
|
||||||
|
switch(ver)
|
||||||
|
{
|
||||||
|
case 0x0e: //cod1
|
||||||
|
break;
|
||||||
|
case 0x14:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Con_Printf(CON_ERROR"%s: unknown version %x\n", mod->name, ver);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Con_Printf(CON_DEBUG"Poses:%i bones:%i flags:%i rate:%i\n", numposes, numrbones, flags, framerate);
|
||||||
|
|
||||||
|
if (flags & 2)
|
||||||
|
numabones = 1;
|
||||||
|
|
||||||
|
mod->type = mod_alias;
|
||||||
|
mod->fromgame = fg_new;
|
||||||
|
mod->meshinfo = surf = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf) + sizeof(*anim) + sizeof(*bone)*(numabones+numrbones));
|
||||||
|
surf->numbones = numabones+numrbones;
|
||||||
|
surf->ofsbones = gbones = plugfuncs->GMalloc(&mod->memgroup, sizeof(*gbones)*(numabones+numrbones));
|
||||||
|
|
||||||
|
surf->numanimations = 1;
|
||||||
|
surf->ofsanimations = anim = (void*)(surf+1);
|
||||||
|
|
||||||
|
anim->loop = !!(flags&1);
|
||||||
|
anim->numposes = numposes;
|
||||||
|
anim->skeltype = SKEL_RELATIVE; //no parents info stored here, so these are screwy unless you're importing them into a model that DOES provide the parents info for you.
|
||||||
|
bone = (void*)(anim+1);
|
||||||
|
anim->rate = framerate;
|
||||||
|
Q_strlcpy(anim->name, mod->name, sizeof(anim->name));
|
||||||
|
anim->GetRawBones = Mod_XAnim_GetRawBones;
|
||||||
|
|
||||||
|
for (i = 0; i < numabones; i++)
|
||||||
|
{
|
||||||
|
gbones[i].parent = -1;
|
||||||
|
VectorClear(gbones[i].ref.org);
|
||||||
|
Vector4Set(gbones[i].ref.quat,0,0,0,1);
|
||||||
|
VectorSet(gbones[i].ref.scale,1,1,1);
|
||||||
|
Q_strlcpy(gbones[i].name, "tag_origin", sizeof(gbones[i].name));
|
||||||
|
|
||||||
|
Mod_XAnim_LoadQuats(mod, &f, &bone[i], numposes, false, true);
|
||||||
|
Mod_XAnim_LoadCoords(mod, &f, &bone[i], numposes);
|
||||||
|
}
|
||||||
|
flip = ReadBytes(&f, (numrbones+7)>>3);
|
||||||
|
tiny = ReadBytes(&f, (numrbones+7)>>3);
|
||||||
|
if (anim->loop)
|
||||||
|
numposes++; //is this the right place?
|
||||||
|
for (i = 0; i < numrbones; i++)
|
||||||
|
{
|
||||||
|
const char *n = ReadString(&f);
|
||||||
|
gbones[numabones+i].parent = -1; //no information. oh noes.
|
||||||
|
VectorClear(gbones[i].ref.org);
|
||||||
|
Vector4Set(gbones[i].ref.quat,0,0,0,1);
|
||||||
|
VectorSet(gbones[i].ref.scale,1,1,1);
|
||||||
|
Q_strlcpy(gbones[numabones+i].name, n, sizeof(gbones[numabones+i].name));
|
||||||
|
// Con_Printf(CON_DEBUG"Part %i = %s (%i %i)\n", numabones+i, bone[numabones+i].name, !!(flip[i>>3]&(1u<<(i&7))), !!(tiny[i>>3]&(1u<<(i&7))));
|
||||||
|
}
|
||||||
|
for (i = 0; i < numrbones; i++)
|
||||||
|
{
|
||||||
|
// Con_Printf(CON_WARNING"%s:\n", gbones[numabones+i].name);
|
||||||
|
Mod_XAnim_LoadQuats(mod, &f, &bone[numabones+i], numposes, !!(flip[i>>3]&(1u<<(i&7))), !!(tiny[i>>3]&(1u<<(i&7))));
|
||||||
|
Mod_XAnim_LoadCoords(mod, &f, &bone[numabones+i], numposes);
|
||||||
|
}
|
||||||
|
if (anim->loop)
|
||||||
|
numposes--;
|
||||||
|
|
||||||
|
numev = ReadByte(&f);
|
||||||
|
if (numev)
|
||||||
|
{
|
||||||
|
anim->events = plugfuncs->GMalloc(&mod->memgroup, sizeof(*anim->events)*(numev));
|
||||||
|
for (i = 0; i < numev; i++)
|
||||||
|
{
|
||||||
|
const char *txt = ReadString(&f);
|
||||||
|
anim->events[i].code = 0; //this format doesn't provide event ids, just pure strings.
|
||||||
|
anim->events[i].data = strcpy(plugfuncs->GMalloc(&mod->memgroup, strlen(txt)+1), txt);
|
||||||
|
|
||||||
|
anim->events[i].timestamp = ReadUInt16(&f) / (float)numposes;
|
||||||
|
}
|
||||||
|
qsort(anim->events, numev, sizeof(*anim->events), Mod_XAnim_CompareEvents); //make sure they're sorted by timestamps.
|
||||||
|
for (i = 0; i < numev-1; i++)
|
||||||
|
anim->events[i].next = &anim->events[i+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.ofs != f.len)
|
||||||
|
Con_Printf(CON_WARNING"Misread %s (%u bytes of %u)\n", mod->name, (unsigned)f.ofs, (unsigned)f.len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
qboolean QDECL Mod_XModel_Load (struct model_s *mod, void *buffer, size_t fsize)
|
||||||
|
{
|
||||||
|
struct fstream_s f = {buffer, fsize};
|
||||||
|
struct fstream_s pf = {NULL,0};
|
||||||
|
unsigned short ver;
|
||||||
|
unsigned i;
|
||||||
|
unsigned int clod, clodnsurf;
|
||||||
|
unsigned short t;
|
||||||
|
struct lod_s lod[4];
|
||||||
|
float mincov = 0;
|
||||||
|
int nlod;
|
||||||
|
|
||||||
|
//I fucking hate this.
|
||||||
|
if (!strncmp(mod->publicname, "xanim/", 6)) //anims are not linked in any way, we treat them as separate precachable models so that gamecode can selectively load them.
|
||||||
|
return Mod_XAnim_Load(mod, buffer, fsize);
|
||||||
|
if (!strncmp(mod->publicname, "xmodelparts/", 12)) //loaded as part of models. don't get confused.
|
||||||
|
return false;
|
||||||
|
if (!strncmp(mod->publicname, "xmodelsurfs/", 12)) //loaded as part of models. don't get confused.
|
||||||
|
return false;
|
||||||
|
//"xmodels/" is okay though!
|
||||||
|
|
||||||
|
ver = ReadUInt16(&f);
|
||||||
|
switch(ver)
|
||||||
|
{
|
||||||
|
case 0x0e: //cod1
|
||||||
|
nlod = 3;
|
||||||
|
break;
|
||||||
|
case 0x14: //cod2
|
||||||
|
/*type =*/ ReadByte(&f);
|
||||||
|
nlod = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Con_Printf(CON_ERROR"%s: Unknown version %x\n", mod->name, ver);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mod->mins[0] = ReadFloat(&f);
|
||||||
|
mod->mins[1] = ReadFloat(&f);
|
||||||
|
mod->mins[2] = ReadFloat(&f);
|
||||||
|
mod->maxs[0] = ReadFloat(&f);
|
||||||
|
mod->maxs[1] = ReadFloat(&f);
|
||||||
|
mod->maxs[2] = ReadFloat(&f);
|
||||||
|
for (i = 0; i < nlod; i++)
|
||||||
|
{
|
||||||
|
lod[i].coverage = ReadFloat(&f); //coverage
|
||||||
|
lod[i].name = ReadString(&f);
|
||||||
|
}
|
||||||
|
clod = ReadUInt32(&f);
|
||||||
|
clodnsurf = ReadUInt32(&f);
|
||||||
|
(void)clod;
|
||||||
|
for (i = 0; i < clodnsurf && !ReadEOF(&f); i++)
|
||||||
|
{
|
||||||
|
unsigned int t, ntris = ReadUInt32(&f);
|
||||||
|
for (t = 0; t < ntris && !ReadEOF(&f); t++)
|
||||||
|
{
|
||||||
|
vec4_t p, sd, td;
|
||||||
|
//plane
|
||||||
|
p[0] = ReadFloat(&f);
|
||||||
|
p[1] = ReadFloat(&f);
|
||||||
|
p[2] = ReadFloat(&f);
|
||||||
|
p[3] = ReadFloat(&f);
|
||||||
|
|
||||||
|
//?splane?
|
||||||
|
sd[0] = ReadFloat(&f);
|
||||||
|
sd[1] = ReadFloat(&f);
|
||||||
|
sd[2] = ReadFloat(&f);
|
||||||
|
sd[3] = ReadFloat(&f);
|
||||||
|
|
||||||
|
//?tplane?
|
||||||
|
td[0] = ReadFloat(&f);
|
||||||
|
td[1] = ReadFloat(&f);
|
||||||
|
td[2] = ReadFloat(&f);
|
||||||
|
td[3] = ReadFloat(&f);
|
||||||
|
|
||||||
|
(void)p;
|
||||||
|
(void)sd;
|
||||||
|
(void)td;
|
||||||
|
|
||||||
|
// Con_Printf("%i: %f %f %f %f : %f %f %f %f : %f %f %f %f\n", t, p[0],p[1],p[2],p[3], sd[0],sd[1],sd[2],sd[3], td[0],td[1],td[2],td[3]);
|
||||||
|
//dunno how to use this for collision... a triangle has 3 side faces AND a front!
|
||||||
|
}
|
||||||
|
//bounds
|
||||||
|
ReadFloat(&f);
|
||||||
|
ReadFloat(&f);
|
||||||
|
ReadFloat(&f);
|
||||||
|
ReadFloat(&f);
|
||||||
|
ReadFloat(&f);
|
||||||
|
ReadFloat(&f);
|
||||||
|
/*boneidx = */ ReadUInt32(&f);
|
||||||
|
/*contents = */ ReadUInt32(&f);
|
||||||
|
/*surfaceflags = */ ReadUInt32(&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
pf.ofs = 0;
|
||||||
|
pf.start = filefuncs->LoadFile(va("xmodelparts/%s", lod[0].name), &pf.len);
|
||||||
|
if (pf.start)
|
||||||
|
{
|
||||||
|
if (!ReadEOF(&pf) && Mod_XModel_LoadPart(mod, &pf))
|
||||||
|
{
|
||||||
|
if (pf.ofs != pf.len)
|
||||||
|
Con_Printf(CON_WARNING"Misread xmodelparts/%s (%u bytes of %u)\n", lod[0].name, (unsigned)f.ofs, (unsigned)f.len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
plugfuncs->Free(pf.start);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nlod; i++)
|
||||||
|
{
|
||||||
|
if (!*lod[i].name)
|
||||||
|
break;
|
||||||
|
lod[i].numtex = ReadUInt16(&f);
|
||||||
|
for (t = 0; t < lod[i].numtex; t++)
|
||||||
|
lod[i].tex[t] = ReadString(&f);
|
||||||
|
pf.ofs = 0;
|
||||||
|
pf.start = filefuncs->LoadFile(va("xmodelsurfs/%s", lod[i].name), &pf.len);
|
||||||
|
if (pf.start)
|
||||||
|
{
|
||||||
|
if (!ReadEOF(&pf) && Mod_XModel_LoadSurfs(mod, &pf, &lod[i], mincov))
|
||||||
|
{
|
||||||
|
if (pf.ofs != pf.len)
|
||||||
|
Con_Printf(CON_WARNING"Misread xmodelsurfs/%s (%u bytes of %u)\n", lod[i].name, (unsigned)f.ofs, (unsigned)f.len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
mincov = lod[i].coverage;
|
||||||
|
plugfuncs->Free(pf.start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mod->type = mod_alias;
|
||||||
|
mod->fromgame = fg_new;
|
||||||
|
mod->radius = RadiusFromBounds(mod->mins, mod->maxs);
|
||||||
|
// if (mod->meshinfo)
|
||||||
|
// modfuncs->BIH_BuildAlias(mod, mod->meshinfo);
|
||||||
|
return !!mod->meshinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean XMODEL_Init(void)
|
||||||
|
{
|
||||||
|
filefuncs = plugfuncs->GetEngineInterface(plugfsfuncs_name, sizeof(*filefuncs));
|
||||||
|
modfuncs = plugfuncs->GetEngineInterface(plugmodfuncs_name, sizeof(*modfuncs));
|
||||||
|
if (modfuncs && modfuncs->version != MODPLUGFUNCS_VERSION)
|
||||||
|
modfuncs = NULL;
|
||||||
|
|
||||||
|
if (modfuncs && filefuncs)
|
||||||
|
{
|
||||||
|
modfuncs->RegisterModelFormatMagic("XMODEL", "\x0e\0",2, Mod_XModel_Load); //cod1
|
||||||
|
modfuncs->RegisterModelFormatMagic("XMODEL", "\x14\0",2, Mod_XModel_Load); //cod2
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
qboolean CODBSP_Init(void);
|
||||||
|
qboolean STypes_Init(void);
|
||||||
|
qboolean IWI_Init(void);
|
||||||
|
//qboolean IWFF_Init(void);
|
||||||
|
|
||||||
|
qboolean Plug_Init(void)
|
||||||
|
{
|
||||||
|
qboolean somethingisokay = false;
|
||||||
|
char plugname[128];
|
||||||
|
strcpy(plugname, "cod");
|
||||||
|
plugfuncs->GetPluginName(0, plugname, sizeof(plugname));
|
||||||
|
|
||||||
|
if (!STypes_Init()) Con_Printf(CON_ERROR"%s: Shader Types support unavailable\n", plugname); else somethingisokay = true;
|
||||||
|
if (!IWI_Init()) Con_Printf(CON_ERROR"%s: IWI support unavailable\n", plugname); else somethingisokay = true;
|
||||||
|
if (!XMODEL_Init()) Con_Printf(CON_ERROR"%s: XModel support unavailable\n", plugname); else somethingisokay = true;
|
||||||
|
if (!CODBSP_Init()) Con_Printf(CON_ERROR"%s: CODBSP support unavailable\n", plugname); else somethingisokay = true;
|
||||||
|
// if (!IWFF_Init()) Con_Printf(CON_ERROR"%s: FF support unavailable\n", plugname); else somethingisokay = true;
|
||||||
|
return somethingisokay;
|
||||||
|
}
|
Loading…
Reference in a new issue