1
0
Fork 0
forked from fte/fteqw

Fix problems with last commit.

Fix rbsp not responding to lightstyle0 consistently.
Fix q2 not responding to any lightstyles.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5599 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2020-01-10 12:23:25 +00:00
parent bfea433dff
commit 73f92fb799
16 changed files with 621 additions and 175 deletions

View file

@ -37,7 +37,7 @@ IF (NOT "${FTE_REVISON}" STREQUAL "")
OUTPUT_VARIABLE FTE_DATE
)
SET(FTE_REVISON SVNREVISION="${FTE_REVISON}" SVNDATE="${FTE_DATE}")
SET(FTE_REVISON SVNREVISION=${FTE_REVISON} SVNDATE="${FTE_DATE}")
ENDIF()
ENDIF()
@ -91,7 +91,7 @@ IF(BZIP2_FOUND)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};AVAIL_BZLIB;BZLIB_STATIC)
SET(FTE_LIBS ${FTE_LIBS} bz2)
SET(FTESV_LIBS ${FTESV_LIBS} bz2)
MESSAGE(STATUS "bzip2 library found. bz2-compressed pk3s will work for the price of extra bloat! yay!")
# MESSAGE(STATUS "bzip2 library found. bz2-compressed pk3s will work for the price of extra bloat! yay!")
ELSE()
MESSAGE(WARNING "bzip2 library NOT available. bz2-compressed pk3s will not be available, as if anyone cares.")
ENDIF()
@ -262,6 +262,10 @@ ELSEIF(${UNIX}) #linux(ish)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11_CURSOR)
MESSAGE(WARNING "Xcursor library NOT available.")
ENDIF()
IF (NOT X11_Xrandr_FOUND)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11_RANDR)
MESSAGE(WARNING "Xrandr library NOT available.")
ENDIF()
ELSE()
MESSAGE(WARNING "x11 library NOT available.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11)

View file

@ -4461,7 +4461,7 @@ static void CLQ2_ParseConfigString (void)
}
else if (i >= Q2CS_LIGHTS && i < Q2CS_LIGHTS+Q2MAX_LIGHTSTYLES)
{
R_UpdateLightStyle(i, s, 1, 1, 1);
R_UpdateLightStyle(i-Q2CS_LIGHTS, s, 1, 1, 1);
}
else if (i == Q2CS_CDTRACK)
{

View file

@ -236,9 +236,9 @@ static qboolean Mod_LoadMap_Proc(model_t *model, char *data)
b[surf].lightmap[2] = -1;
b[surf].lightmap[3] = -1;
b[surf].lmlightstyle[0] = 0;
b[surf].lmlightstyle[1] = 255;
b[surf].lmlightstyle[2] = 255;
b[surf].lmlightstyle[3] = 255;
b[surf].lmlightstyle[1] = INVALID_LIGHTSTYLE;
b[surf].lmlightstyle[2] = INVALID_LIGHTSTYLE;
b[surf].lmlightstyle[3] = INVALID_LIGHTSTYLE;
data = COM_ParseOut(data, token, sizeof(token));
b[surf].shader = R_RegisterShader_Vertex(token);

View file

@ -3199,12 +3199,16 @@ static qboolean CModQ3_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l)
out->light_s[0] = LittleLong(in->lightmap_x);
out->light_t[0] = LittleLong(in->lightmap_y);
out->styles[0] = 255;
out->styles[0] = INVALID_LIGHTSTYLE;
out->vlstyles[0] = 255;
for (sty = 1; sty < MAXRLIGHTMAPS; sty++)
{
out->styles[sty] = 255;
out->styles[sty] = INVALID_LIGHTSTYLE;
out->vlstyles[sty] = 255;
out->lightmaptexturenums[sty] = -1;
}
for (; sty < MAXQ1LIGHTMAPS; sty++)
out->styles[sty] = INVALID_LIGHTSTYLE;
out->lmshift = LMSHIFT_DEFAULT;
//fixme: determine texturemins from lightmap_origin
out->extents[0] = (LittleLong(in->lightmap_width)-1)<<out->lmshift;
@ -3315,11 +3319,14 @@ static qboolean CModRBSP_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l)
out->lightmaptexturenums[j] = LittleLong(in->lightmapnum[j]);
out->light_s[j] = LittleLong(in->lightmap_offs[0][j]);
out->light_t[j] = LittleLong(in->lightmap_offs[1][j]);
out->styles[j] = in->lm_styles[j];
out->styles[j] = (in->lm_styles[j]!=255)?in->lm_styles[j]:INVALID_LIGHTSTYLE;
out->vlstyles[j] = in->vt_styles[j];
if (mod->lightmaps.count < out->lightmaptexturenums[j]+1)
mod->lightmaps.count = out->lightmaptexturenums[j]+1;
}
for (; j < MAXQ1LIGHTMAPS; j++)
out->styles[j] = INVALID_LIGHTSTYLE;
if (facetype == MST_FLARE)
out->texinfo = mod->texinfo + mod->numtexinfo*2;
else if (out->lightmaptexturenums[0]<0 || r_vertexlight.value)

View file

@ -3641,7 +3641,7 @@ static void BE_Program_Set_Attributes(const program_t *prog, struct programpermu
for (j = 0; j < MAXRLIGHTMAPS ; j++)
{
s = shaderstate.curbatch->lmlightstyle[j];
if (s == 255)
if (s == INVALID_LIGHTSTYLE)
{
for (; j < MAXRLIGHTMAPS ; j++)
{
@ -3672,6 +3672,7 @@ static void BE_Program_Set_Attributes(const program_t *prog, struct programpermu
else
#endif
{
unsigned short s;
if (shaderstate.curentity->model && (shaderstate.curentity->model->engineflags & MDLF_NEEDOVERBRIGHT) && !shaderstate.force2d)
{
float sc = (1<<bound(0, gl_overbright.ival, 2)) * shaderstate.identitylighting;
@ -3682,6 +3683,10 @@ static void BE_Program_Set_Attributes(const program_t *prog, struct programpermu
Vector4Set(param4, shaderstate.identitylighting, shaderstate.identitylighting, shaderstate.identitylighting, 1);
}
s = shaderstate.curbatch->lmlightstyle[0]; //only one style.
if (s != INVALID_LIGHTSTYLE)
VectorScale(param4, d_lightstylevalue[s]/256.0f, param4);
qglUniform4fvARB(ph, 1, (GLfloat*)param4);
}
break;

View file

@ -161,10 +161,8 @@ static void Mod_BatchList_f(void)
else if (batch->lightmap[1] >= 0)
Con_Printf("^2 lm=(%i:%i %i:%i)", batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1]);
else
if (batch->lightmap[1] >= 0)
#else
if (batch->lmlightstyle[0] != 255)
#endif
if (batch->lmlightstyle[0] != INVALID_LIGHTSTYLE)
Con_Printf("^2 lm=(%i:%i)", batch->lightmap[0], batch->lmlightstyle[0]);
else
Con_Printf("^2 lm=%i", batch->lightmap[0]);
@ -3255,7 +3253,7 @@ static void Mod_Batches_AllocLightmaps(model_t *mod)
for (sty = 0; sty < MAXRLIGHTMAPS; sty++)
{
batch->lightmap[sty] = surf->lightmaptexturenums[sty];
batch->lmlightstyle[sty] = 255;//don't do special backend rendering of lightstyles.
batch->lmlightstyle[sty] = INVALID_LIGHTSTYLE;//don't do special backend rendering of lightstyles.
batch->vtlightstyle[sty] = 255;//don't do special backend rendering of lightstyles.
}

View file

@ -731,6 +731,7 @@ reeval:
st = &pr_statements[s];
if (prinst.pr_depth == prinst.exitdepth)
{
prinst.pr_xstatement = s;
return -1; // all done
}
return s;

View file

@ -1552,7 +1552,7 @@ void PR_Init(void)
Cmd_AddCommand ("extensionlist_ssqc", PR_SVExtensionList_f);
Cmd_AddCommand ("pr_dumpplatform", PR_DumpPlatform_f);
Cmd_AddCommand ("sv_lightstyle", PR_Lightstyle_f);
Cmd_AddCommandD ("sv_lightstyle", PR_Lightstyle_f, "Overrides lightstyles from the server's console, mostly for debug use.");
/*
#ifdef _DEBUG
@ -4721,30 +4721,52 @@ static void QCBUILTIN PF_lightstyle (pubprogfuncs_t *prinst, struct globalvars_s
static void PR_Lightstyle_f(void)
{
int style = atoi(Cmd_Argv(1));
if (svs.gametype != GT_PROGS && svs.gametype != GT_Q1QVM)
Con_TPrintf ("not supported in the current game mode.\n");
else if (!SV_MayCheat())
if (!SV_MayCheat())
Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n");
else if (Cmd_Argc() <= 2)
else switch(svs.gametype)
{
if (style >= 0 && style < sv.maxlightstyles && Cmd_Argc() >= 2)
Con_Printf("Style %i: %s %g %g %g\n", style, sv.lightstyles[style].str, sv.lightstyles[style].colours[0], sv.lightstyles[style].colours[1], sv.lightstyles[style].colours[2]);
else for (style = 0; style < sv.maxlightstyles; style++)
if (sv.lightstyles[style].str)
Con_Printf("Style %i: %s %g %g %g\n", style, sv.lightstyles[style].str, sv.lightstyles[style].colours[0], sv.lightstyles[style].colours[1], sv.lightstyles[style].colours[2]);
}
else
{
vec3_t rgb = {1,1,1};
if (Cmd_Argc() > 5)
default:
Con_TPrintf ("not supported in the current game mode.\n");
break;
#ifdef Q2SERVER
case GT_QUAKE2:
if (Cmd_Argc() <= 2)
{
rgb[0] = atof(Cmd_Argv(3));
rgb[1] = atof(Cmd_Argv(4));
rgb[2] = atof(Cmd_Argv(5));
if ((unsigned)style < (unsigned)Q2MAX_LIGHTSTYLES && Cmd_Argc() >= 2)
Con_Printf ("Style %i: %s\n", style, sv.strings.configstring[Q2CS_LIGHTS+style]);
else for (style = 0; style < Q2MAX_LIGHTSTYLES; style++)
if (sv.strings.configstring[Q2CS_LIGHTS+style])
Con_Printf("Style %i: %s\n", style, sv.strings.configstring[Q2CS_LIGHTS+style]);
}
else if (Cmd_Argc() > 3)
rgb[0] = rgb[1] = rgb[2] = atof(Cmd_Argv(3));
PF_applylightstyle(style, Cmd_Argv(2), rgb);
else if ((unsigned)style < (unsigned)Q2MAX_LIGHTSTYLES)
PFQ2_Configstring (Q2CS_LIGHTS+style, Cmd_Argv(2));
break;
#endif
case GT_PROGS:
case GT_Q1QVM:
if (Cmd_Argc() <= 2)
{
if (style >= 0 && style < sv.maxlightstyles && Cmd_Argc() >= 2)
Con_Printf("Style %i: %s %g %g %g\n", style, sv.lightstyles[style].str, sv.lightstyles[style].colours[0], sv.lightstyles[style].colours[1], sv.lightstyles[style].colours[2]);
else for (style = 0; style < sv.maxlightstyles; style++)
if (sv.lightstyles[style].str)
Con_Printf("Style %i: %s %g %g %g\n", style, sv.lightstyles[style].str, sv.lightstyles[style].colours[0], sv.lightstyles[style].colours[1], sv.lightstyles[style].colours[2]);
}
else
{
vec3_t rgb = {1,1,1};
if (Cmd_Argc() > 5)
{
rgb[0] = atof(Cmd_Argv(3));
rgb[1] = atof(Cmd_Argv(4));
rgb[2] = atof(Cmd_Argv(5));
}
else if (Cmd_Argc() > 3)
rgb[0] = rgb[1] = rgb[2] = atof(Cmd_Argv(3));
PF_applylightstyle(style, Cmd_Argv(2), rgb);
}
break;
}
}

View file

@ -1270,6 +1270,7 @@ qboolean SV_FilterImpulse(int imp, int level);
//svq2_game.c
qboolean SVQ2_InitGameProgs(void);
void VARGS SVQ2_ShutdownGameProgs (void);
void VARGS PFQ2_Configstring (int i, const char *val); //for engine cheats.
//svq2_ents.c
void SVQ2_BuildClientFrame (client_t *client);

View file

@ -1538,7 +1538,7 @@ void SV_SendLightstyle(client_t *cl, sizebuf_t *forcemsg, int style, qboolean in
if (!(cl->fteprotocolextensions & PEXT_LIGHTSTYLECOL))
{ //if they don't support it then just drop the extra colours, so long as it still makes sense.
if ((flags & ~0x87u) || (ISNQCLIENT(cl) && !ISDPCLIENT(cl) && !cl->fteprotocolextensions2))
if ((flags & ~0x87u) && (ISNQCLIENT(cl) && !ISDPCLIENT(cl) && cl->fteprotocolextensions2))
{
char *text = va("//ls %i \"%s\" %g %g %g\n", style, sv.lightstyles[style].str, sv.lightstyles[style].colours[0], sv.lightstyles[style].colours[1], sv.lightstyles[style].colours[2]);
if (forcemsg)
@ -1551,7 +1551,9 @@ void SV_SendLightstyle(client_t *cl, sizebuf_t *forcemsg, int style, qboolean in
ClientReliable_FinishWrite(cl);
return; //erk, can't handle this!
}
flags = 7;
if (style >= ((cl->fteprotocolextensions2||ISDPCLIENT(cl))?255:64))
return; //client probably doesn't support this lightstyle.
flags = 7; //force vanilla protocol as fallback.
}
if (forcemsg)

View file

@ -291,7 +291,7 @@ PF_Configstring
===============
*/
static void VARGS PFQ2_Configstring (int i, const char *val)
void VARGS PFQ2_Configstring (int i, const char *val)
{
if (i < 0 || i >= Q2MAX_CONFIGSTRINGS)
Sys_Error ("configstring: bad index %i\n", i);

374
imgtool.c
View file

@ -4,6 +4,7 @@
#define stderr stdout
#include <limits.h>
#include <ctype.h>
#ifdef _WIN32
#include <windows.h>
#endif
@ -348,11 +349,29 @@ static void ImgTool_FreeMips(struct pendingtextureinfo *mips)
sh_config_t sh_config;
viddef_t vid;
static const char *imagetypename[] = {"2D", "3D", "Cube", "2DArray", "CubemapArray", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"};
typedef struct
{
unsigned int offset; // Position of the entry in WAD
unsigned int dsize; // Size of the entry in WAD file
unsigned int size; // Size of the entry in memory
char type; // type of entry
char cmprs; // Compression. 0 if none.
short dummy; // Not used
char name[16]; // we use only first 8
} wad2entry_t;
typedef struct
{
char magic[4]; //should be WAD2
unsigned int num; //number of entries
unsigned int offset; //location of directory
} wad2_t;
static const char *imagetypename[] = {"2D", "3D", "Cube", "2DArray", "CubemapArray", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"};
struct opts_s
{
int textype;
const char *defaultext; //.dds or whatever when the output's extension is not explicitly given.
unsigned int flags; //image flags to use (affects how textures get interpreted a little)
unsigned int mipnum; //when exporting to a mipless format, this is the mip level that is actually written. default 0.
uploadfmt_t newpixelformat; //try to convert to this pixel format on export.
@ -376,23 +395,16 @@ static enum uploadfmt ImgTool_ASTCToLDR(uploadfmt_t fmt)
return fmt;
}
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
static void FS_MakeTempName(char *out, size_t outsize, char *prefix, char *suffix)
{
int fd;
unsigned int n;
unsigned int s = rand();
for (n = 0; n < 0xffffff; n++)
{
Q_snprintfz(out, outsize, "/tmp/%s%06x%s", prefix, (n+s)&0xffffff, suffix);
fd = _open(out, _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
if (fd == -1)
continue;
close(fd);
return;
}
Sys_Error("FS_MakeTempName failed\n");
static char temp_path[MAX_PATH];
char temp_file_name[MAX_PATH];
if (!*temp_path && !GetTempPathA(sizeof(temp_path), temp_path))
Sys_Error("FS_MakeTempName failed to get temp path\n");
if (!GetTempFileNameA(temp_path, prefix, 0, temp_file_name))
Sys_Error("FS_MakeTempName failed\n");
Q_snprintfz(out, outsize, "%s%s", temp_file_name, suffix);
}
#else
#include <unistd.h>
@ -402,6 +414,58 @@ static void FS_MakeTempName(char *out, size_t outsize, char *prefix, char *suffi
close(mkstemps(out, strlen(suffix))); //bsd4.3/posix1-2001
}
#endif
static qboolean ImgTool_HasAlpha(struct pendingtextureinfo *mips)
{
if (mips->encoding == PTI_RGBA8 || mips->encoding == PTI_BGRA8 || mips->encoding == PTI_LLLA8 || mips->encoding == PTI_RGBA8_SRGB || mips->encoding == PTI_BGRA8_SRGB)
{
size_t l = 0, pixels, p;
qbyte *d;
for (l = 0; l < mips->mipcount; l++)
{
pixels = mips->mip[l].width * mips->mip[l].height * mips->mip[l].depth * 4;
d = mips->mip[l].data;
d+=3;
for (p = 0; p < pixels; p+=4)
if (d[p] != 255)
return true; //a transparent pixel!
}
return false;
}
else if (mips->encoding == PTI_L8A8 || mips->encoding == PTI_L8A8_SRGB)
{
size_t l = 0, pixels, p;
qbyte *d;
for (l = 0; l < mips->mipcount; l++)
{
pixels = mips->mip[l].width * mips->mip[l].height * mips->mip[l].depth * 2;
d = mips->mip[l].data;
d+=1;
for (p = 0; p < pixels; p+=2)
if (d[p] != 255)
return true; //a transparent pixel!
}
return false;
}
else if (mips->encoding == PTI_RGBA16)
{
size_t l = 0, pixels, p;
unsigned short *d;
for (l = 0; l < mips->mipcount; l++)
{
pixels = mips->mip[l].width * mips->mip[l].height * mips->mip[l].depth * 4;
d = mips->mip[l].data;
d+=3;
for (p = 0; p < pixels; p+=4)
if (d[p] != 0xffff)
return true; //a transparent pixel!
}
return false;
}
else
return Image_FormatHasAlpha(mips->encoding);
}
static qboolean ImgTool_ConvertPixelFormat(struct opts_s *args, const char *inname, struct pendingtextureinfo *mips)
{
struct pendingtextureinfo tmp, *ret;
@ -415,10 +479,10 @@ static qboolean ImgTool_ConvertPixelFormat(struct opts_s *args, const char *inna
int bb,bw,bh;
qboolean canktx = false;
uploadfmt_t targfmt = args->newpixelformat;
int d,l, layers;
int d,l, layers, r;
//force it to bc1 if bc2 or bc3 with no alpha channel.
if ((targfmt == PTI_BC2_RGBA || targfmt == PTI_BC3_RGBA) && !Image_FormatHasAlpha(mips->encoding))
if ((targfmt == PTI_BC2_RGBA || targfmt == PTI_BC3_RGBA) && !ImgTool_HasAlpha(mips))
targfmt = PTI_BC1_RGB;
if (targfmt >= PTI_ASTC_FIRST && targfmt <= PTI_ASTC_LAST)
@ -428,12 +492,20 @@ static qboolean ImgTool_ConvertPixelFormat(struct opts_s *args, const char *inna
}
else if (targfmt == PTI_BC1_RGB)
Q_snprintfz(command, sizeof(command), "nvcompress -bc1%s", (args->flags&IF_TRYBUMP)?"n":"");
else if (targfmt == PTI_BC1_RGB_SRGB)
Q_snprintfz(command, sizeof(command), "nvcompress -bc1%s -srgb -dds10", (args->flags&IF_TRYBUMP)?"n":"");
else if (targfmt == PTI_BC1_RGBA)
Q_snprintfz(command, sizeof(command), "nvcompress -bc1a");
else if (targfmt == PTI_BC1_RGBA_SRGB)
Q_snprintfz(command, sizeof(command), "nvcompress -bc1a -srgb -dds10");
else if (targfmt == PTI_BC2_RGBA)
Q_snprintfz(command, sizeof(command), "nvcompress -bc2");
else if (targfmt == PTI_BC2_RGBA_SRGB)
Q_snprintfz(command, sizeof(command), "nvcompress -bc2 -srgb -dds10");
else if (targfmt == PTI_BC3_RGBA)
Q_snprintfz(command, sizeof(command), "nvcompress -bc3%s", (args->flags&IF_TRYBUMP)?"n":"");
else if (targfmt == PTI_BC3_RGBA_SRGB)
Q_snprintfz(command, sizeof(command), "nvcompress -bc3%s -srgb -dds10", (args->flags&IF_TRYBUMP)?"n":"");
else if (targfmt == PTI_BC4_R8)
Q_snprintfz(command, sizeof(command), "nvcompress -bc4");
else if (targfmt == PTI_BC5_RG8)
@ -442,6 +514,8 @@ static qboolean ImgTool_ConvertPixelFormat(struct opts_s *args, const char *inna
Q_snprintfz(command, sizeof(command), "nvcompress -bc6");
else if (targfmt == PTI_BC7_RGBA)
Q_snprintfz(command, sizeof(command), "nvcompress -bc7");
else if (targfmt == PTI_BC7_RGBA_SRGB)
Q_snprintfz(command, sizeof(command), "nvcompress -bc7 -srgb");
else
{
if (mips->encoding != targfmt)
@ -487,8 +561,12 @@ static qboolean ImgTool_ConvertPixelFormat(struct opts_s *args, const char *inna
Q_strncatz(command, " -hdr", sizeof(command));
if (targfmt >= PTI_BC1_RGB && targfmt <= PTI_BC7_RGBA_SRGB && (strstr(inname, "_n.")||strstr(inname, "_norm.")))
Q_strncatz(command, " -normal", sizeof(command)); //looks like a normalmap... tweak metrics to favour normalised results.
Q_strncatz(command, ">> /dev/null", sizeof(command));
#ifdef _WIN32
Q_strncatz(command, "> NUL 2>&1", sizeof(command));
#else
Q_strncatz(command, ">> /dev/null", sizeof(command));
#endif
if (!canktx)
{
@ -549,7 +627,12 @@ static qboolean ImgTool_ConvertPixelFormat(struct opts_s *args, const char *inna
break;
}
system(command);
r = system(command);
if (r != EXIT_SUCCESS)
{
Con_Printf("The following system command failed with code %i: %s\n", r, command);
break;
}
fdata = FS_LoadMallocFile(comp, &fsize);
ret = Image_LoadMipsFromMemory(IF_NOMIPMAP, comp, comp, fdata, fsize);
@ -608,7 +691,7 @@ const char *COM_GetFileExtension (const char *in, const char *term)
if (*dot == '.')
return dot;
}
return "";
return term+strlen(term);
}
static struct pendingtextureinfo *ImgTool_Read(struct opts_s *args, const char *inname)
{
@ -845,9 +928,21 @@ static struct pendingtextureinfo *ImgTool_Combine(struct opts_s *args, const cha
static void ImgTool_Convert(struct opts_s *args, struct pendingtextureinfo *in, const char *inname, const char *outname)
{
size_t k;
const char *outext = COM_GetFileExtension(outname, NULL);
const char *outext;
qboolean allowcompressed = false;
char newout[MAX_OSPATH];
if (!outname)
{
outext = COM_GetFileExtension(inname, NULL);
k = min(MAX_OSPATH-2-strlen(args->defaultext), outext-inname);
memcpy(newout, inname, k);
newout[k++] = '.';
strcpy(newout+k, args->defaultext);
outname = newout;
}
outext = COM_GetFileExtension(outname, NULL);
if (!strcmp(outext, ".dds") || !strcmp(outext, ".ktx"))
allowcompressed = true;
@ -918,7 +1013,7 @@ static void ImgTool_Convert(struct opts_s *args, struct pendingtextureinfo *in,
/*(k == PTI_L16) ||*/
(k == PTI_BGR8) || (k == PTI_BGR8) ||
0;
if (!sh_config.texfmt[in->encoding])
if (!outformats[in->encoding])
{
Image_ChangeFormat(in, outformats, PTI_INVALID, outname);
printf("\t(Exporting as %s)\n", Image_FormatName(in->encoding));
@ -974,6 +1069,35 @@ static void ImgTool_Info(struct opts_s *args, const char *inname)
indata = FS_LoadMallocFile(inname, &fsize);
if (!indata)
printf("%s: unable to read\n", inname);
else if (fsize >= sizeof(wad2_t) && indata[0] == 'W' && indata[1] == 'A' && indata[2] == 'D')
{
const wad2_t *w = (const wad2_t *)indata;
const wad2entry_t *e = (const wad2entry_t *)(indata+w->offset);
printf("%s: wad%c file with %i entries\n", inname, w->magic[3], w->num);
for (m = 0; m < w->num; m++, e++)
{
switch(e->type)
{
case 67: //hl...
case TYP_MIPTEX:
{
const miptex_t *mip = (const miptex_t *)(indata+e->offset);
/*mip name SHOULD match entry name... but gah!*/
if (strcasecmp(e->name, mip->name))
printf("\t%16.16s (%s): %u*%u%s\n", e->name, mip->name, mip->width, mip->height, mip->offsets[0]?"":" (external data)");
else
printf("\t%16.16s: %u*%u%s\n", mip->name, mip->width, mip->height, mip->offsets[0]?"":" (external data)");
}
break;
case TYP_PALETTE:
printf("\t%16.16s: palette - %u bytes\n", e->name, e->size);
break;
default:
printf("\t%16.16s: ENTRY TYPE %u (%u bytes)\n", e->name, e->type, e->size);
break;
}
}
}
else
{
in = Image_LoadMipsFromMemory(args->flags, inname, inname, indata, fsize);
@ -996,6 +1120,7 @@ struct filelist_s
const char **exts;
size_t numfiles;
struct {
const char *rootpath; //the basepath that was passed to the filelist scan.
char *name;
size_t baselen; //length up to but not including the filename extension.
} *file;
@ -1010,7 +1135,7 @@ static void FileList_Release(struct filelist_s *list)
list->numfiles = 0;
list->maxfiles = 0;
}
static void FileList_Add(struct filelist_s *list, char *fname)
static void FileList_Add(struct filelist_s *list, const char *rootpath, char *fname)
{
size_t i;
size_t baselen;
@ -1036,15 +1161,47 @@ static void FileList_Add(struct filelist_s *list, char *fname)
list->maxfiles += 64;
list->file = realloc(list->file, sizeof(*list->file)*list->maxfiles);
}
list->file[i].rootpath = rootpath;
list->file[i].name = strdup(fname);
list->file[i].baselen = baselen;
list->numfiles++;
}
#ifdef _WIN32
static void ImgTool_TreeScan(struct filelist_s *list, const char *basepath, const char *subpath)
{
(void)FileList_Add;
Con_Printf("ImgTool_TreeScan not implemented on windows.\n");
static void ImgTool_TreeScan(struct filelist_s *list, const char *rootpath, const char *subpath)
{ //FIXME: convert to utf-8.
HANDLE h;
WIN32_FIND_DATAA fd;
char file[MAX_OSPATH];
if (subpath && *subpath)
Q_snprintfz(file, sizeof(file), "%s/%s", rootpath, subpath);
else
Q_snprintfz(file, sizeof(file), "%s", rootpath);
if (GetFileAttributesA(file) & FILE_ATTRIBUTE_DIRECTORY) //if its a directory then scan it.
Q_snprintfz(file+strlen(file), sizeof(file)-strlen(file), "/*");
h = FindFirstFileA(file, &fd);
if (h != INVALID_HANDLE_VALUE)
{
do
{
if (*fd.cFileName == '.')
continue; //skip .. (and unix hidden files, because urgh)
if (subpath && *subpath)
Q_snprintfz(file, sizeof(file), "%s/%s", subpath, fd.cFileName);
else
Q_snprintfz(file, sizeof(file), "%s", fd.cFileName);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
; //don't report hidden entries.
else if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
ImgTool_TreeScan(list, rootpath, file);
else
FileList_Add(list, rootpath, file);
} while(FindNextFileA(h, &fd));
FindClose(h);
}
}
#else
#include <dirent.h>
@ -1088,13 +1245,13 @@ static void ImgTool_TreeScan(struct filelist_s *list, const char *basepath, cons
Q_snprintfz(file, sizeof(file), "%s/%s", subpath, ent->d_name);
else
Q_snprintfz(file, sizeof(file), "%s", ent->d_name);
FileList_Add(list, file);
FileList_Add(list, basepath, file);
}
}
closedir(dir);
}
#endif
static void ImgTool_TreeConvert(struct opts_s *args, const char *srcpath, const char *destpath)
static void ImgTool_TreeConvert(struct opts_s *args, const char *destpath, const char *srcpath)
{
size_t newfiles=0, skippedfiles=0, processedfiles=0;
char file[MAX_OSPATH];
@ -1145,25 +1302,55 @@ static void ImgTool_TreeConvert(struct opts_s *args, const char *srcpath, const
typedef struct
static void ImgTool_WadExtract(struct opts_s *args, const char *wadname)
{
unsigned int offset; // Position of the entry in WAD
unsigned int dsize; // Size of the entry in WAD file
unsigned int size; // Size of the entry in memory
char type; // type of entry
char cmprs; // Compression. 0 if none.
short dummy; // Not used
char name[16]; // we use only first 8
} wad2entry_t;
typedef struct
{
char magic[4]; //should be WAD2
unsigned int num; //number of entries
unsigned int offset; //location of directory
} wad2_t;
static void ImgTool_WadConvert(struct opts_s *args, const char *srcpath, const char *destpath, int wadtype/*x,2,3*/)
qbyte *indata;
size_t fsize;
size_t m;
indata = FS_LoadMallocFile(wadname, &fsize);
if (!indata)
printf("%s: unable to read\n", wadname);
else if (fsize >= sizeof(wad2_t) && indata[0] == 'W' && indata[1] == 'A' && indata[2] == 'D')
{
const wad2_t *w = (const wad2_t *)indata;
const wad2entry_t *e = (const wad2entry_t *)(indata+w->offset);
for (m = 0; m < w->num; m++, e++)
{
switch(e->type)
{
case 67: //hl...
case TYP_MIPTEX:
{
miptex_t *mip = (miptex_t *)(indata+e->offset);
struct pendingtextureinfo *out = Z_Malloc(sizeof(*out));
out->encoding = PTI_P8;
out->type = PTI_2D;
for (out->mipcount = 0; out->mipcount < 4 && mip->offsets[out->mipcount]; out->mipcount++)
{
out->mip[out->mipcount].width = mip->width>>out->mipcount;
out->mip[out->mipcount].height = mip->height>>out->mipcount;
out->mip[out->mipcount].depth = 1;
out->mip[out->mipcount].datasize = out->mip[out->mipcount].width*out->mip[out->mipcount].height*out->mip[out->mipcount].depth;
out->mip[out->mipcount].data = (char*)mip + mip->offsets[out->mipcount];
}
if (*mip->name == '*')
*mip->name = '#'; //convert from * to #, so its a valid file name.
ImgTool_Convert(args, out, mip->name, NULL);
}
break;
case TYP_PALETTE:
default:
printf("skipping %s\n", e->name);
break;
}
}
}
else
printf("%s: does not appear to be a wad file\n", wadname);
}
static void ImgTool_WadConvert(struct opts_s *args, const char *destpath, const char **srcpaths, size_t numpaths, int wadtype/*x,2,3*/)
{
char file[MAX_OSPATH];
const char *exts[] = {".png", ".bmp", ".tga", ".exr", ".hdr", ".dds", ".ktx", ".xcf", ".pcx", ".jpg", NULL};
@ -1179,7 +1366,16 @@ static void ImgTool_WadConvert(struct opts_s *args, const char *srcpath, const c
miptex_t mip;
qboolean wadpixelformats[PTI_MAX] = {0};
wadpixelformats[PTI_P8] = true;
ImgTool_TreeScan(&list, srcpath, NULL);
if (!numpaths)
ImgTool_TreeScan(&list, ".", NULL);
else while(numpaths --> 0)
ImgTool_TreeScan(&list, *srcpaths++, NULL);
if (!list.numfiles)
{
printf("%s: No files specified\n", destpath);
return;
}
f = FS_OpenVFS(destpath, "wb", FS_SYSTEM);
wad2.magic[0] = 'W';
@ -1194,9 +1390,26 @@ static void ImgTool_WadConvert(struct opts_s *args, const char *srcpath, const c
for (u = 1; u < countof(sh_config.texfmt); u++)
sh_config.texfmt[u] = (u==PTI_RGBA8)||(u==PTI_RGBX8)||(u==PTI_P8);
if (wadtype == 2)
{ //WAD2 files generally have a palette lump.
if (wad2.num == maxentries)
{
maxentries += 64;
wadentries = realloc(wadentries, sizeof(*wadentries)*maxentries);
}
entry = &wadentries[wad2.num++];
memset(entry, 0, sizeof(*entry));
Q_strncpyz(entry->name, "PALETTE", 16);
entry->type = TYP_PALETTE;
entry->offset = VFS_TELL(f);
//and the lump data.
VFS_WRITE(f, host_basepal, 256*3);
}
for (i = 0; i < list.numfiles; i++)
{
Q_snprintfz(file, sizeof(file), "%s/%s", srcpath, list.file[i].name);
Q_snprintfz(file, sizeof(file), "%s/%s", list.file[i].rootpath, list.file[i].name);
inname = list.file[i].name;
if (list.file[i].baselen > 15)
{
@ -1204,7 +1417,9 @@ static void ImgTool_WadConvert(struct opts_s *args, const char *srcpath, const c
continue;
}
indata = FS_LoadMallocFile(file, &fsize);
if (indata)
if (!indata)
printf("Unable to open %s\n", inname);
else
{
struct pendingtextureinfo *in = Image_LoadMipsFromMemory(args->flags, inname, file, indata, fsize);
Image_GenerateMips(in, args->flags);
@ -1276,7 +1491,14 @@ static void ImgTool_WadConvert(struct opts_s *args, const char *srcpath, const c
entry->name[list.file[i].baselen] = 0; //kill any .tga
if (*entry->name == '#')
*entry->name = '*'; //* is not valid in a filename, yet needed for turbs, so by convention # is used instead. this is only relevant for the first char.
entry->type = TYP_MIPTEX;
if (wadtype == 3)
{
for (u = 0; u < sizeof(entry->name); u++)
entry->name[u] = toupper(entry->name[u]);
entry->type = 67;
}
else
entry->type = TYP_MIPTEX;
entry->cmprs = 0;
entry->dummy = 0;
entry->offset = VFS_TELL(f);
@ -1326,6 +1548,7 @@ int main(int argc, const char **argv)
mode_genwadx,
mode_genwad2,
mode_genwad3,
mode_extractwad,
} mode = mode_info;
size_t u, f;
qboolean nomoreopts = false;
@ -1338,6 +1561,7 @@ int main(int argc, const char **argv)
args.newpixelformat = PTI_INVALID;
args.mipnum = 0;
args.textype = -1;
args.defaultext = NULL;
sh_config.texture2d_maxsize = 1u<<31;
sh_config.texture3d_maxsize = 1u<<31;
@ -1364,13 +1588,14 @@ int main(int argc, const char **argv)
else if (!strcmp(argv[u], "-?") || !strcmp(argv[u], "--help"))
{
showhelp:
Con_Printf("show info : %s -i *.ktx\n", argv[0]);
Con_Printf("compress : %s --astc_6x6_ldr [--nomips] in.png out.ktx [in2.png out2.ktx]\n", argv[0]);
Con_Printf("compress : %s --bc3_rgba [--premul] [--nomips] in.png out.dds\n\tConvert pixel format (to bc3 aka dxt5) before writing to output file.\n", argv[0]);
Con_Printf("convert : %s --convert in.exr out.dds\n\tConvert to different file format, while trying to preserve pixel formats.\n", argv[0]);
Con_Printf("recursive : %s --astc_6x6_ldr -r srcdir destdir\n", argv[0]);
Con_Printf("decompress: %s --decompress [--exportmip 0] [--nomips] in.ktx out.png\n\tDecompresses any block-compressed pixel data.\n", argv[0]);
Con_Printf("gen wad : %s --genwad3 [--exportmip 2] srcdir out.wad\n", argv[0]);
Con_Printf("show info : %s -i *.ktx\n", argv[0]);
Con_Printf("compress : %s --astc_6x6_ldr [--nomips] in.png out.ktx [in2.png out2.ktx]\n", argv[0]);
Con_Printf("compress : %s --bc3_rgba [--premul] [--nomips] in.png out.dds\n\tConvert pixel format (to bc3 aka dxt5) before writing to output file.\n", argv[0]);
Con_Printf("convert : %s --convert in.exr out.dds\n\tConvert to different file format, while trying to preserve pixel formats.\n", argv[0]);
Con_Printf("recursive : %s --auto --astc_6x6_ldr destdir srcdir\n\tCompresses the files to dds (writing to an optionally different directory)", argv[0]);
Con_Printf("decompress : %s --decompress [--exportmip 0] [--nomips] in.ktx out.png\n\tDecompresses any block-compressed pixel data.\n", argv[0]);
Con_Printf("create wad : %s -w [--exportmip 2] out.wad srcdir\n", argv[0]);
Con_Printf("extract wad: %s -x [--ext png] src.wad\n", argv[0]);
Image_PrintInputFormatVersions();
Con_Printf("Supported compressed/interesting pixelformats are:\n");
@ -1426,6 +1651,8 @@ showhelp:
mode = mode_genwad2;
else if (!files && (!strcmp(argv[u], "-w") || !strcmp(argv[u], "--genwadx")))
mode = mode_genwadx;
else if (!files && (!strcmp(argv[u], "-x") || !strcmp(argv[u], "--extractwad")))
mode = mode_extractwad;
else if (!strcmp(argv[u], "--2d"))
args.textype = PTI_2D;
else if (!strcmp(argv[u], "--3d"))
@ -1444,6 +1671,16 @@ showhelp:
args.flags |= IF_PREMULTIPLYALPHA;
else if (!strcmp(argv[u], "--nopremul"))
args.flags &= ~IF_PREMULTIPLYALPHA;
else if (!strcmp(argv[u], "--ext"))
{
if (u+1 < argc)
args.defaultext = argv[++u];
else
{
Con_Printf("--exportmip requires trailing numeric argument\n");
return 1;
}
}
else if (!strcmp(argv[u], "--exportmip"))
{
char *e = "erk";
@ -1480,6 +1717,14 @@ showhelp:
argv[files++] = argv[u];
}
if (!args.defaultext)
{
if (mode == mode_extractwad)
args.defaultext = "png"; //something the user expects to be able to view easily (and lossless)
else
args.defaultext = "ktx";
}
if (mode == mode_info)
{ //just print info about each listed file.
for (u = 0; u < files; u++)
@ -1500,10 +1745,15 @@ showhelp:
}
else if (mode == mode_autotree && files == 2)
ImgTool_TreeConvert(&args, argv[0], argv[1]);
else if ((mode == mode_genwad2 || mode == mode_genwad3 || mode == mode_genwadx) && files == 2)
ImgTool_WadConvert(&args, argv[0], argv[1], mode-mode_genwadx);
else if ((mode == mode_genwad2 || mode == mode_genwad3 || mode == mode_genwadx))
ImgTool_WadConvert(&args, argv[0], argv+1, files-1, mode-mode_genwadx);
else if ((mode == mode_extractwad) && files == 1)
ImgTool_WadExtract(&args, argv[0]);
else
{
printf("%u files\n", (int)files);
printf("unsupported arg count for mode\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View file

@ -326,6 +326,6 @@ NATIVE_PLUGINS+=ezhud
$(PLUG_PREFIX)models$(PLUG_NATIVE_EXT): models/gltf.c models/exportiqm.c models/models.c plugin.c
$(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -o $@ -shared $(PLUG_CFLAGS) -Imodels $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS)
#NATIVE_PLUGINS+=models
NATIVE_PLUGINS+=models
all: $(foreach FOO,$(NATIVE_PLUGINS), $(PLUG_PREFIX)$(FOO)$(PLUG_NATIVE_EXT))

View file

@ -116,17 +116,19 @@ static AVStream *add_video_stream(struct encctx *ctx, AVCodec *codec, int fps, i
int forcewidth = ffmpeg_videoforcewidth->value;
int forceheight = ffmpeg_videoforceheight->value;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
st = avformat_new_stream(ctx->fc, NULL);
if (!st)
return NULL;
st->id = ctx->fc->nb_streams-1;
c = avcodec_alloc_context3(codec);
#else
st = avformat_new_stream(ctx->fc, codec);
if (!st)
return NULL;
st->id = ctx->fc->nb_streams-1;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
c = st->codec;
#else
c = avcodec_alloc_context3(codec);
if(avcodec_parameters_to_context(c, st->codecpar))
return NULL;
st->id = ctx->fc->nb_streams-1;
#endif
ctx->video_codec = c;
c->codec_id = codec->id;
@ -166,7 +168,6 @@ static AVStream *add_video_stream(struct encctx *ctx, AVCodec *codec, int fps, i
if (*ffmpeg_video_crf->string)
av_opt_set(c->priv_data, "crf", ffmpeg_video_crf->string, AV_OPT_SEARCH_CHILDREN);
return st;
}
static void close_video(struct encctx *ctx)
@ -301,18 +302,22 @@ static AVStream *add_audio_stream(struct encctx *ctx, AVCodec *codec, int *sampl
AVStream *st;
int bitrate = ffmpeg_audiobitrate->value;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
st = avformat_new_stream(ctx->fc, codec);
if (!st)
return NULL;
st->id = ctx->fc->nb_streams-1;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
c = st->codec;
#else
st = avformat_new_stream(ctx->fc, NULL);
if (!st)
return NULL;
c = avcodec_alloc_context3(codec);
if(avcodec_parameters_to_context(c, st->codecpar))
return NULL;
#endif
st->id = ctx->fc->nb_streams-1;
ctx->audio_codec = c;
c->codec_id = codec->id;
c->codec_type = codec->type;
@ -645,6 +650,16 @@ static void *AVEnc_Begin (char *streamname, int videorate, int width, int height
ctx->video_outbuf = av_malloc(ctx->video_outbuf_size);
if (!ctx->video_outbuf)
ctx->video_outbuf_size = 0;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
//copy the avcodec parameters over to avformat
err = avcodec_parameters_from_context(ctx->video_st->codecpar, c);
if(err < 0)
{
AVEnc_End(ctx);
return NULL;
}
#endif
}
if (ctx->audio_st)
{
@ -717,9 +732,6 @@ static void AVEnc_End (void *vctx)
}
#endif
close_video(ctx);
close_audio(ctx);
//don't write trailers if this is an error case and we never even wrote the headers.
if (ctx->doneheaders)
{
@ -728,12 +740,15 @@ static void AVEnc_End (void *vctx)
Con_Printf("Finished writing %s\n", ctx->abspath);
}
close_video(ctx);
close_audio(ctx);
for(i = 0; i < ctx->fc->nb_streams; i++)
av_freep(&ctx->fc->streams[i]);
// if (!(fmt->flags & AVFMT_NOFILE))
avio_close(ctx->fc->pb);
av_free(ctx->audio_outbuf);
av_free(ctx->fc);
avformat_free_context(ctx->fc);
free(ctx);
}
static media_encoder_funcs_t encoderfuncs =
@ -741,7 +756,7 @@ static media_encoder_funcs_t encoderfuncs =
sizeof(media_encoder_funcs_t),
"ffmpeg",
"Use ffmpeg's various codecs. Various settings are configured with the "ENCODERNAME"_* cvars.",
".mp4",
".mp4;.*",
AVEnc_Begin,
AVEnc_Video,
AVEnc_Audio,

View file

@ -42,7 +42,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "ezquakeisms.h"
#include "hud.h"
//#define WITH_PNG
//#define WITH_PNG //more WITH_RADAR than anything else.
#define draw_disc draw_disc2

View file

@ -1,5 +1,5 @@
#ifndef GLQUAKE
//#define GLQUAKE //this is shit.
#define GLQUAKE //this is shit, but ensures index sizes come out the right size
#endif
#include "quakedef.h"
#include "../plugin.h"
@ -7,10 +7,38 @@
extern plugmodfuncs_t *modfuncs;
extern plugfsfuncs_t *filefuncs;
#if MAX_INDICIES == 0xffffu
#warning 16bit indexes
#else
#warning 32bit indexes
#endif
#ifdef SKELETALMODELS
#define GLTFMODELS
#endif
/*Limitations:
materials:
material names (when present) are assumed to be either globally unique, or the material attributes must match those of all other materials with the same name.
texture modes (like clamp) must match on both axis (either both clamp or both wrap, no mixing)
mirrored-repeat not supported
mip-mag-mip filters must match (all linear, or all nearest)
animations:
input framerates are not well-defined. this can result in issues when converting to other formats (especially with stepping anims).
morph targets are not supported.
total nodes(+joints) must be < MAX_BONES, and ideally <MAX_GPU_BONES too but it is sufficient for that to be per-mesh.
meshes:
multiple texture coord sets are not supported.
additional colours/weights attributes are not supported.
multiple meshes with the same material will not be merged.
scene:
cameras can be parsed, but are not necessarily useful as they are not exposed to the gamecode.
extensions:
no KHR_draco_mesh_compression
unknown extensions will result in warning spam for each occurence.
gltf1 is NOT supported, only gltf2.
*/
//'The units for all linear distances are meters.'
//'feh: 1 metre is approx. 26.24671916 qu.'
@ -536,9 +564,6 @@ static size_t JSON_ReadBody(json_t *t, char *out, size_t outsize)
//glTF 1.0 and 2.0 differ in that 1 uses names and 2 uses indexes. There's also some significant differences with materials.
//we only support 2.0
//articulated models are handled by loading them as skeletal (should probably optimise the engine for this usecase)
//we don't support skeletal models either right now.
//buffers are raw blobs that can come from multiple different sources
struct gltf_buffer
{
@ -820,6 +845,7 @@ static void GLTF_AccessorToTangents(gltf_t *gltf, vec3_t *norm, vec3_t **sdir, v
char *in = a->data;
size_t v, c;
float side;
*sdir = os;
*tdir = ot;
if ((a->type&0xff) != 4)
@ -833,9 +859,37 @@ static void GLTF_AccessorToTangents(gltf_t *gltf, vec3_t *norm, vec3_t **sdir, v
memset(os, 0, sizeof(*os) * outverts);
memset(ot, 0, sizeof(*ot) * outverts);
break;
// case 5120: //BYTE
// case 5121: //UNSIGNED_BYTE
// case 5122: //SHORT
case 5120: //BYTE KHR_mesh_quantization (always normalized)
for (v = 0; v < outverts; v++)
{
for (c = 0; c < 3; c++)
os[v][c] = max(-1.0, ((signed char*)in)[c] / 127.0); //negative values are larger, but we want to allow 1.0
side = max(-1.0, ((signed char*)in)[3] / 127.0);
//bitangent = cross(normal, tangent.xyz) * tangent.w
ot[v][0] = (norm[v][1]*os[v][2] - norm[v][2]*os[v][1]) * side;
ot[v][1] = (norm[v][2]*os[v][0] - norm[v][0]*os[v][2]) * side;
ot[v][2] = (norm[v][0]*os[v][1] - norm[v][1]*os[v][0]) * side;
in += a->bytestride;
}
break;
// case 5121: //UNSIGNED_BYTE
case 5122: //SHORT KHR_mesh_quantization (always normalized)
for (v = 0; v < outverts; v++)
{
for (c = 0; c < 3; c++)
os[v][c] = max(-1.0, ((signed short*)in)[c] / 32767.0);
side = max(-1.0, ((signed short*)in)[3] / 32767.0);
//bitangent = cross(normal, tangent.xyz) * tangent.w
ot[v][0] = (norm[v][1]*os[v][2] - norm[v][2]*os[v][1]) * side;
ot[v][1] = (norm[v][2]*os[v][0] - norm[v][0]*os[v][2]) * side;
ot[v][2] = (norm[v][0]*os[v][1] - norm[v][1]*os[v][0]) * side;
in += a->bytestride;
}
break;
// case 5123: //UNSIGNED_SHORT
// case 5125: //UNSIGNED_INT
case 5126: //FLOAT
@ -843,17 +897,19 @@ static void GLTF_AccessorToTangents(gltf_t *gltf, vec3_t *norm, vec3_t **sdir, v
{
for (c = 0; c < 3; c++)
os[v][c] = ((float*)in)[c];
side = ((float*)in)[3];
//bitangent = cross(normal, tangent.xyz) * tangent.w
ot[v][0] = (norm[v][1]*os[v][2] - norm[v][2]*os[v][1]) * ((float*)in)[3];
ot[v][1] = (norm[v][2]*os[v][0] - norm[v][0]*os[v][2]) * ((float*)in)[3];
ot[v][2] = (norm[v][0]*os[v][1] - norm[v][1]*os[v][0]) * ((float*)in)[3];
ot[v][0] = (norm[v][1]*os[v][2] - norm[v][2]*os[v][1]) * side;
ot[v][1] = (norm[v][2]*os[v][0] - norm[v][0]*os[v][2]) * side;
ot[v][2] = (norm[v][0]*os[v][1] - norm[v][1]*os[v][0]) * side;
in += a->bytestride;
}
break;
}
}
static void *GLTF_AccessorToDataF(gltf_t *gltf, size_t outverts, unsigned int outcomponents, struct gltf_accessor *a)
{
float *ret = modfuncs->ZG_Malloc(&gltf->mod->memgroup, sizeof(*ret) * outcomponents * outverts), *o;
@ -872,58 +928,133 @@ static void *GLTF_AccessorToDataF(gltf_t *gltf, size_t outverts, unsigned int ou
memset(ret, 0, sizeof(*ret) * outcomponents * outverts);
break;
case 5120: //BYTE
while(outverts --> 0)
if (!a->normalized)
{ //KHR_mesh_quantization
while(outverts --> 0)
{
for (c = 0; c < ic; c++)
o[c] = ((signed char*)in)[c];
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
}
}
else
{
for (c = 0; c < ic; c++)
o[c] = max(-1.0, ((char*)in)[c] / 127.0); //negative values are larger, but we want to allow 1.0
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
while(outverts --> 0)
{
for (c = 0; c < ic; c++)
o[c] = max(-1.0, ((signed char*)in)[c] / 127.0); //negative values are larger, but we want to allow 1.0
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
}
}
break;
case 5121: //UNSIGNED_BYTE
while(outverts --> 0)
if (!a->normalized)
{ //KHR_mesh_quantization
while(outverts --> 0)
{
for (c = 0; c < ic; c++)
o[c] = ((unsigned char*)in)[c];
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
}
}
else
{
for (c = 0; c < ic; c++)
o[c] = ((unsigned char*)in)[c] / 255.0;
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
while(outverts --> 0)
{
for (c = 0; c < ic; c++)
o[c] = ((unsigned char*)in)[c] / 255.0;
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
}
}
break;
case 5122: //SHORT
while(outverts --> 0)
if (!a->normalized)
{ //KHR_mesh_quantization
while(outverts --> 0)
{
for (c = 0; c < ic; c++)
o[c] = ((signed short*)in)[c];
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
}
}
else
{
for (c = 0; c < ic; c++)
o[c] = max(-1.0, ((signed short*)in)[c] / 32767.0); //negative values are larger, but we want to allow 1.0
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
while(outverts --> 0)
{
for (c = 0; c < ic; c++)
o[c] = max(-1.0, ((signed short*)in)[c] / 32767.0); //negative values are larger, but we want to allow 1.0
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
}
}
break;
case 5123: //UNSIGNED_SHORT
while(outverts --> 0)
if (!a->normalized)
{ //KHR_mesh_quantization
while(outverts --> 0)
{
for (c = 0; c < ic; c++)
o[c] = ((unsigned short*)in)[c];
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
}
}
else
{
for (c = 0; c < ic; c++)
o[c] = ((unsigned short*)in)[c] / 65535.0;
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
while(outverts --> 0)
{
for (c = 0; c < ic; c++)
o[c] = ((unsigned short*)in)[c] / 65535.0;
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
}
}
break;
case 5125: //UNSIGNED_INT
while(outverts --> 0)
if (!a->normalized)
{ //?!?!?!?!
while(outverts --> 0)
{
for (c = 0; c < ic; c++)
o[c] = ((unsigned int*)in)[c];
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
}
}
else
{
for (c = 0; c < ic; c++)
o[c] = ((unsigned int*)in)[c] / (double)~0u; //stupid format to use. will be lossy.
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
while(outverts --> 0)
{
for (c = 0; c < ic; c++)
o[c] = ((unsigned int*)in)[c] / (double)~0u; //stupid format to use. will be lossy.
for (; c < outcomponents; c++)
o[c] = 0;
o += outcomponents;
in += a->bytestride;
}
}
break;
case 5126: //FLOAT
@ -997,15 +1128,18 @@ static void *GLTF_AccessorToDataBone(gltf_t *gltf, size_t outverts, struct gltf_
if (ic > outcomponents)
ic = outcomponents;
o = ret;
if (a->normalized)
if (gltf->warnlimit --> 0)
Con_Printf(CON_WARNING"GLTF_AccessorToDataBone: %s: normalised input\n", gltf->mod->name);
switch(a->componentType)
{
default:
if (gltf->warnlimit --> 0)
Con_Printf(CON_WARNING"GLTF_AccessorToDataUB: %s: glTF2 unsupported componentType (%i)\n", gltf->mod->name, a->componentType);
Con_Printf(CON_WARNING"GLTF_AccessorToDataBone: %s: glTF2 unsupported componentType (%i)\n", gltf->mod->name, a->componentType);
case 0:
memset(ret, 0, sizeof(*ret) * outcomponents * outverts);
break;
// case 5120: //BYTE
case 5120: //BYTE - should not be negative, so ignore sign bit
case 5121: //UNSIGNED_BYTE
while(outverts --> 0)
{
@ -1021,7 +1155,7 @@ static void *GLTF_AccessorToDataBone(gltf_t *gltf, size_t outverts, struct gltf_
in += a->bytestride;
}
break;
case 5122: //SHORT
case 5122: //SHORT - should not be negative, so ignore sign bit
case 5123: //UNSIGNED_SHORT
while(outverts --> 0)
{
@ -1256,8 +1390,10 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
JSON_ReadBody(nam, ret->frame->shadername, sizeof(ret->frame->shadername));
else if (mat)
JSON_GetPath(mat, false, ret->frame->shadername, sizeof(ret->frame->shadername));
else if (material == -1) //explicit invalid material
Q_snprintf(ret->frame->shadername, sizeof(ret->frame->shadername), "%s", gltf->mod->name);
else
Q_snprintf(ret->frame->shadername, sizeof(ret->frame->shadername), "%i", material);
Q_snprintf(ret->frame->shadername, sizeof(ret->frame->shadername), "%.100s/%i", gltf->mod->name, material);
if (alphaMode == 1)
Q_snprintf(alphaCutoffmodifier, sizeof(alphaCutoffmodifier), "#ALPHATEST=>%f", alphaCutoff);
@ -1374,8 +1510,9 @@ static galiasskin_t *GLTF_LoadMaterial(gltf_t *gltf, int material, qboolean vert
JSON_GetFloat(mat, "emissiveFactor.2", 0)
);
}
else if (pbrmr)
else// if (pbrmr)
{ //this is the standard lighting model for gltf2
//'When not specified, all the default values of pbrMetallicRoughness apply'
int albedo = JSON_GetInteger(pbrmr, "baseColorTexture.index", -1); //.rgba
int mrt = JSON_GetInteger(pbrmr, "metallicRoughnessTexture.index", -1); //.r = unused, .g = roughness, .b = metalic, .a = unused
int occ = JSON_GetInteger(mat, "occlusionTexture.index", -1); //.r
@ -2197,16 +2334,18 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
static struct
{
const char *name;
qboolean supported; //unsupported extensions don't really need to be listed, but they do prevent warnings from unkown-but-used extensions
qboolean supported; //unsupported extensions don't really need to be listed, but they do prevent warnings from unknown-but-used extensions
qboolean draft; //true when our implementation is probably buggy on account of the spec maybe changing.
} extensions[] =
{
{"KHR_materials_pbrSpecularGlossiness", true},
//draft {"KHR_materials_cmnBlinnPhong", true},
{"KHR_materials_unlit", true},
{"KHR_texture_transform", false},
{"KHR_draco_mesh_compression", false},
{"MSFT_texture_dds", true},
{"MSFT_packing_occlusionRoughnessMetallic", true},
{"KHR_materials_pbrSpecularGlossiness", true, false},
// {"KHR_materials_cmnBlinnPhong", true, true},
{"KHR_materials_unlit", true, false},
{"KHR_texture_transform", false, true}, //probably not fatal
{"KHR_draco_mesh_compression", false, true}, //probably fatal
{"KHR_mesh_quantization", true, true},
{"MSFT_texture_dds", true, false},
{"MSFT_packing_occlusionRoughnessMetallic", true, false},
};
gltf_t gltf;
int pos=0, j, k;
@ -2267,6 +2406,8 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
}
if (j==countof(extensions) || !extensions[j].supported)
Con_Printf(CON_WARNING "%s: gltf2 extension \"%s\" not known\n", mod->name, extname);
else if (extensions[j].draft)
Con_Printf(CON_WARNING "%s: gltf2 extension \"%s\" follows draft implementation, and may be non-standard/buggy\n", mod->name, extname);
}
VectorClear(mod->maxs);