fteqw/plugins/cod/codmat.c
2024-07-14 19:58:25 +01:00

244 lines
9 KiB
C

#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));
}