- model command migrated

This commit is contained in:
Christoph Oelckers 2021-04-21 00:00:14 +02:00
parent 542e1b2ba7
commit 8c854441bc
2 changed files with 245 additions and 418 deletions

View file

@ -142,14 +142,6 @@ enum scripttoken_t
T_SURFACE, T_VIEW,
};
static int32_t lastmodelid = -1, modelskin = -1, lastmodelskin = -1, seenframe = 0;
static const char *skyfaces[6] =
{
"front face", "right face", "back face",
"left face", "top face", "bottom face"
};
static int32_t defsparser(scriptfile *script);
static void defsparser_include(const char *fn, scriptfile *script, FScriptPosition *pos)
@ -433,416 +425,7 @@ static int32_t defsparser(scriptfile *script)
// NEW (ENCOURAGED) DEFINITION SYNTAX
case T_MODEL:
{
FScanner::SavedPos modelend;
FString modelfn;
double scale=1.0, mzadd=0.0, myoffset=0.0;
int32_t shadeoffs=0, pal=0, flags=0;
uint8_t usedframebitmap[(1024+7)>>3];
int32_t model_ok = 1;
static const tokenlist modeltokens[] =
{
{ "scale", T_SCALE },
{ "shade", T_SHADE },
{ "zadd", T_ZADD },
{ "yoffset", T_YOFFSET },
{ "frame", T_FRAME },
{ "anim", T_ANIM },
{ "skin", T_SKIN },
{ "detail", T_DETAIL },
{ "glow", T_GLOW },
{ "specular", T_SPECULAR },
{ "normal", T_NORMAL },
{ "hud", T_HUD },
{ "flags", T_FLAGS },
};
memset(usedframebitmap, 0, sizeof(usedframebitmap));
modelskin = lastmodelskin = 0;
seenframe = 0;
if (scriptfile_getstring(script,&modelfn)) break;
if (scriptfile_getbraces(script,&modelend)) break;
lastmodelid = md_loadmodel(modelfn);
if (lastmodelid < 0)
{
Printf("Warning: Failed loading MD2/MD3 model \"%s\"\n", modelfn.GetChars());
scriptfile_setposition(script, modelend);
break;
}
while (!scriptfile_endofblock(script, modelend))
{
int32_t token = getatoken(script,modeltokens,countof(modeltokens));
switch (token)
{
//case T_ERROR: Printf("Error on line %s:%d in model tokens\n", script->filename,script->linenum); break;
case T_SCALE:
scriptfile_getdouble(script,&scale); break;
case T_SHADE:
scriptfile_getnumber(script,&shadeoffs); break;
case T_ZADD:
scriptfile_getdouble(script,&mzadd); break;
case T_YOFFSET:
scriptfile_getdouble(script,&myoffset); break;
case T_FLAGS:
scriptfile_getnumber(script,&flags); break;
case T_FRAME:
{
auto framepos = scriptfile_getposition(script);
FScanner::SavedPos frameend;
FString framename;
char happy=1;
int32_t tilex = 0, framei;
int32_t ftilenume = -1, ltilenume = -1;
double smoothduration = 0.1f;
static const tokenlist modelframetokens[] =
{
{ "pal", T_PAL },
{ "frame", T_FRAME },
{ "name", T_FRAME },
{ "tile", T_TILE },
{ "tile0", T_TILE0 },
{ "tile1", T_TILE1 },
{ "smoothduration", T_SMOOTHDURATION },
};
if (scriptfile_getbraces(script,&frameend)) break;
while (!scriptfile_endofblock(script, frameend))
{
switch (getatoken(script,modelframetokens,countof(modelframetokens)))
{
case T_PAL:
scriptfile_getsymbol(script,&pal); break;
case T_FRAME:
scriptfile_getstring(script,&framename); break;
case T_TILE:
scriptfile_getsymbol(script,&ftilenume); ltilenume = ftilenume; break;
case T_TILE0:
scriptfile_getsymbol(script,&ftilenume); break; //first tile number
case T_TILE1:
scriptfile_getsymbol(script,&ltilenume); break; //last tile number (inclusive)
case T_SMOOTHDURATION:
scriptfile_getdouble(script,&smoothduration); break;
}
}
if (check_tile_range("model: frame", &ftilenume, &ltilenume, script, pos))
{
model_ok = 0;
break;
}
if (lastmodelid < 0)
{
framepos.Message(MSG_WARNING, "ignoring frame definition");
break;
}
if (smoothduration > 1.0)
{
framepos.Message(MSG_WARNING, "smoothduration out of range");
smoothduration = 1.0;
}
for (tilex = ftilenume; tilex <= ltilenume && happy; tilex++)
{
framei = md_defineframe(lastmodelid, framename, tilex, max(0,modelskin), smoothduration,pal);
switch (framei)
{
case -1:
happy = 0; break; // invalid model id!?
case -2:
framepos.Message(MSG_WARNING, "Invalid tile number");
happy = 0;
break;
case -3:
framepos.Message(MSG_WARNING, "%s: Invalid frame name", framename.GetChars());
happy = 0;
break;
default:
if (framei >= 0 && framei<1024)
usedframebitmap[framei>>3] |= (1 << (framei&7));
}
model_ok &= happy;
}
seenframe = 1;
}
break;
case T_ANIM:
{
auto animpos = scriptfile_getposition(script);
FScanner::SavedPos animend;
FString startframe, endframe;
int happy=1;
int32_t flags = 0;
double dfps = 1.0;
static const tokenlist modelanimtokens[] =
{
{ "frame0", T_FRAME0 },
{ "frame1", T_FRAME1 },
{ "fps", T_FPS },
{ "flags", T_FLAGS },
};
if (scriptfile_getbraces(script,&animend)) break;
while (!scriptfile_endofblock(script, animend))
{
switch (getatoken(script,modelanimtokens,countof(modelanimtokens)))
{
case T_FRAME0:
scriptfile_getstring(script,&startframe); break;
case T_FRAME1:
scriptfile_getstring(script,&endframe); break;
case T_FPS:
scriptfile_getdouble(script,&dfps); break; //animation frame rate
case T_FLAGS:
scriptfile_getsymbol(script,&flags); break;
}
}
if (startframe.IsEmpty()) animpos.Message(MSG_ERROR, "missing 'start frame' for anim definition"), happy = 0;
if (endframe.IsEmpty()) animpos.Message(MSG_ERROR, "missing 'end frame' for anim definition"), happy = 0;
model_ok &= happy;
if (!happy) break;
if (lastmodelid < 0)
{
Printf("Warning: Ignoring animation definition.\n");
break;
}
switch (md_defineanimation(lastmodelid, startframe, endframe, (int32_t)(dfps*(65536.0*.001)), flags))
{
case 0:
break;
case -1:
break; // invalid model id!?
case -2:
pos.Message(MSG_ERROR, "Invalid starting frame name");
model_ok = 0;
break;
case -3:
pos.Message(MSG_ERROR, "Invalid ending frame name");
model_ok = 0;
break;
case -4:
pos.Message(MSG_ERROR, "Out of memory");
model_ok = 0;
break;
}
}
break;
case T_SKIN: case T_DETAIL: case T_GLOW: case T_SPECULAR: case T_NORMAL:
{
auto skinpos = scriptfile_getposition(script);
FScanner::SavedPos skinend;
FString skinfn;
int32_t palnum = 0, surfnum = 0;
double param = 1.0, specpower = 1.0, specfactor = 1.0;
int32_t flags = 0;
static const tokenlist modelskintokens[] =
{
{ "pal", T_PAL },
{ "file", T_FILE },
{ "surf", T_SURF },
{ "surface", T_SURF },
{ "intensity", T_PARAM },
{ "scale", T_PARAM },
{ "detailscale", T_PARAM },
{ "specpower", T_SPECPOWER }, { "specularpower", T_SPECPOWER }, { "parallaxscale", T_SPECPOWER },
{ "specfactor", T_SPECFACTOR }, { "specularfactor", T_SPECFACTOR }, { "parallaxbias", T_SPECFACTOR },
{ "nocompress", T_NOCOMPRESS },
{ "nodownsize", T_NODOWNSIZE },
{ "forcefilter", T_FORCEFILTER },
{ "artquality", T_ARTQUALITY },
};
if (scriptfile_getbraces(script,&skinend)) break;
while (!scriptfile_endofblock(script, skinend))
{
switch (getatoken(script,modelskintokens,countof(modelskintokens)))
{
case T_PAL:
scriptfile_getsymbol(script,&palnum); break;
case T_PARAM:
scriptfile_getdouble(script,&param); break;
case T_SPECPOWER:
scriptfile_getdouble(script,&specpower); break;
case T_SPECFACTOR:
scriptfile_getdouble(script,&specfactor); break;
case T_FILE:
scriptfile_getstring(script,&skinfn); break; //skin filename
case T_SURF:
scriptfile_getnumber(script,&surfnum); break;
}
}
if (skinfn.IsEmpty())
{
skinpos.Message(MSG_ERROR, "missing 'skin filename' for skin definition");
model_ok = 0;
break;
}
if (seenframe) { modelskin = ++lastmodelskin; }
seenframe = 0;
switch (token)
{
case T_DETAIL:
palnum = DETAILPAL;
param = 1.0f / param;
break;
case T_GLOW:
palnum = GLOWPAL;
break;
case T_SPECULAR:
palnum = SPECULARPAL;
break;
case T_NORMAL:
palnum = NORMALPAL;
break;
}
if (!fileSystem.FileExists(skinfn))
break;
switch (md_defineskin(lastmodelid, skinfn, palnum, max(0,modelskin), surfnum, param, specpower, specfactor, flags))
{
case 0:
break;
case -1:
break; // invalid model id!?
case -2:
skinpos.Message(MSG_ERROR, "Invalid skin filename");
model_ok = 0;
break;
case -3:
skinpos.Message(MSG_ERROR, "Invalid palette number");
model_ok = 0;
break;
case -4:
skinpos.Message(MSG_ERROR, "Out of memory");
model_ok = 0;
break;
}
}
break;
case T_HUD:
{
auto hudpos = scriptfile_getposition(script);
FScanner::SavedPos frameend;
char happy=1;
int32_t tilex = 0;
int32_t ftilenume = -1, ltilenume = -1, flags = 0, fov = -1, angadd = 0;
double xadd = 0.0, yadd = 0.0, zadd = 0.0;
static const tokenlist modelhudtokens[] =
{
{ "tile", T_TILE },
{ "tile0", T_TILE0 },
{ "tile1", T_TILE1 },
{ "xadd", T_XADD },
{ "yadd", T_YADD },
{ "zadd", T_ZADD },
{ "angadd", T_ANGADD },
{ "fov", T_FOV },
{ "hide", T_HIDE },
{ "nobob", T_NOBOB },
{ "flipped",T_FLIPPED},
{ "nodepth",T_NODEPTH},
};
if (scriptfile_getbraces(script,&frameend)) break;
while (!scriptfile_endofblock(script, frameend))
{
switch (getatoken(script,modelhudtokens,countof(modelhudtokens)))
{
case T_TILE:
scriptfile_getsymbol(script,&ftilenume); ltilenume = ftilenume; break;
case T_TILE0:
scriptfile_getsymbol(script,&ftilenume); break; //first tile number
case T_TILE1:
scriptfile_getsymbol(script,&ltilenume); break; //last tile number (inclusive)
case T_XADD:
scriptfile_getdouble(script,&xadd); break;
case T_YADD:
scriptfile_getdouble(script,&yadd); break;
case T_ZADD:
scriptfile_getdouble(script,&zadd); break;
case T_ANGADD:
scriptfile_getsymbol(script,&angadd); break;
case T_FOV:
scriptfile_getsymbol(script,&fov); break;
case T_HIDE:
flags |= HUDFLAG_HIDE; break;
case T_NOBOB:
flags |= HUDFLAG_NOBOB; break;
case T_FLIPPED:
flags |= HUDFLAG_FLIPPED; break;
case T_NODEPTH:
flags |= HUDFLAG_NODEPTH; break;
}
}
if (check_tile_range("hud", &ftilenume, &ltilenume, script, hudpos))
{
model_ok = 0;
break;
}
if (lastmodelid < 0)
{
hudpos.Message(MSG_WARNING, "Ignoring frame definition.");
break;
}
for (tilex = ftilenume; tilex <= ltilenume && happy; tilex++)
{
vec3f_t const add = { (float)xadd, (float)yadd, (float)zadd };
switch (md_definehud(lastmodelid, tilex, add, angadd, flags, fov))
{
case 0:
break;
case -1:
happy = 0; break; // invalid model id!?
case -2:
hudpos.Message(MSG_ERROR, "Invalid tile number");
happy = 0;
break;
case -3:
hudpos.Message(MSG_ERROR, "Invalid frame name");
happy = 0;
break;
}
model_ok &= happy;
}
}
break;
}
}
if (!model_ok)
{
if (lastmodelid >= 0)
{
pos.Message(MSG_ERROR, "Removing model %d due to errors.", lastmodelid);
md_undefinemodel(lastmodelid);
nextmodelid--;
}
break;
}
md_setmisc(lastmodelid,(float)scale,shadeoffs,(float)mzadd,(float)myoffset,flags);
modelskin = lastmodelskin = 0;
seenframe = 0;
}
parseModel(*script, pos);
break;
case T_VOXEL:
parseVoxel(*script, pos);

View file

@ -1745,3 +1745,247 @@ void parseUndefModelOf(FScanner& sc, FScriptPosition& pos)
if (!ValidateTilenum("undefmodelof", tile, pos)) return;
pos.Message(MSG_WARNING, "undefmodelof: currently non-functional.");
}
//===========================================================================
//
//
//
//===========================================================================
static bool parseModelFrameBlock(FScanner& sc, FixedBitArray<1024>& usedframes)
{
FScanner::SavedPos blockend;
FScriptPosition pos = sc;
FString framename;
bool ok = true;
int pal = -1;
int starttile = -1, endtile = -1;
double smoothduration = 0.1f;
if (sc.StartBraces(&blockend)) return false;
while (!sc.FoundEndBrace(blockend))
{
sc.MustGetString();
if (sc.Compare("pal")) sc.GetNumber(pal, true);
else if (sc.Compare({ "name", "frame" })) sc.GetString(framename);
else if (sc.Compare("tile")) { sc.GetNumber(starttile, true); endtile = starttile; }
else if (sc.Compare("tile0")) sc.GetNumber(starttile, true);
else if (sc.Compare("tile1")) sc.GetNumber(endtile, true);
else if (sc.Compare("smoothduration")) sc.GetFloat(smoothduration, true);
}
if (!ValidateTileRange("model: frame", starttile, endtile, pos)) return false;
if (smoothduration > 1.0)
{
pos.Message(MSG_WARNING, "smoothduration out of range");
smoothduration = 1.0;
}
for (int i = starttile; i <= endtile && ok; i++)
{
int res = md_defineframe(mdglobal.lastmodelid, framename, i, max(0, mdglobal.modelskin), smoothduration, pal);
if (res < 0)
{
ok = false;
if (res == -2) pos.Message(MSG_WARNING, "Invalid tile number %d", i);
else if (res == -3) pos.Message(MSG_WARNING, "%s: Invalid frame name", framename.GetChars());
}
else if (res < 1024) usedframes.Set(res);
}
mdglobal.seenframe = 1;
return ok;
}
static bool parseModelAnimBlock(FScanner& sc)
{
FScanner::SavedPos blockend;
FScriptPosition pos = sc;
FString startframe, endframe;
int flags = 0;
double fps = 1.0;
if (sc.StartBraces(&blockend)) return false;
while (!sc.FoundEndBrace(blockend))
{
sc.MustGetString();
if (sc.Compare("frame0")) sc.GetString(startframe);
else if (sc.Compare("frame1")) sc.GetString(endframe);
else if (sc.Compare("fps")) sc.GetFloat(fps, true);
else if (sc.Compare("flags")) sc.GetNumber(flags, true);
}
if (startframe.IsEmpty())
{
pos.Message(MSG_ERROR, "missing start frame for anim definition");
return false;
}
if (endframe.IsEmpty())
{
pos.Message(MSG_ERROR, "missing end frame for anim definition");
return false;
}
int res = md_defineanimation(mdglobal.lastmodelid, startframe, endframe, (int)(fps * (65536.0 * .001)), flags);
if (res < 0)
{
if (res == -2) pos.Message(MSG_ERROR, "Invalid starting frame name %s", startframe.GetChars());
else if (res == -3) pos.Message(MSG_ERROR, "Invalid ending frame name %s", endframe.GetChars());
return false;
}
return true;
}
static bool parseModelSkinBlock(FScanner& sc, int whichpal)
{
FScanner::SavedPos blockend;
FScriptPosition pos = sc;
FString filename;
int pal = 0, surface = 0;
double param = 1.0, specpower = 1.0, specfactor = 1.0;
int flags = 0;
if (sc.StartBraces(&blockend)) return false;
while (!sc.FoundEndBrace(blockend))
{
sc.MustGetString();
if (sc.Compare("pal")) sc.GetNumber(pal, true);
else if (sc.Compare("file")) sc.GetString(filename);
else if (sc.Compare({ "surface", "surf" })) sc.GetNumber(surface, true);
else if (sc.Compare({ "intensity", "scale", "detailscale" })) sc.GetFloat(param, true);
else if (sc.Compare({ "specpower", "specularpower", "parallaxscale" })) sc.GetFloat(specpower, true);
else if (sc.Compare({ "specfactor", "specularfactor", "parallaxbias" })) sc.GetFloat(specfactor, true);
else if (sc.Compare("forcefilter")) { /* not suppoted yet*/ }
}
if (filename.IsEmpty())
{
pos.Message(MSG_ERROR, "missing 'skin filename' for skin definition");
return false;
}
if (mdglobal.seenframe) mdglobal.modelskin = ++mdglobal.lastmodelskin;
mdglobal.seenframe = 0;
if (!fileSystem.FileExists(filename))
{
pos.Message(MSG_ERROR, "%s: file not found", filename.GetChars());
return false;
}
if (whichpal == DETAILPAL) param = 1. / param;
int res = md_defineskin(mdglobal.lastmodelid, filename, pal, max(0, mdglobal.modelskin), surface, param, specpower, specfactor, flags);
if (res < 0)
{
if (res == -2) pos.Message(MSG_ERROR, "Invalid skin filename %s", filename.GetChars());
else if (res == -3) pos.Message(MSG_ERROR, "Invalid palette number %d", pal);
return false;
}
return true;
}
static bool parseModelHudBlock(FScanner& sc)
{
FScanner::SavedPos blockend;
FScriptPosition pos = sc;
int starttile = -1, endtile = -1, flags = 0, fov = -1, angadd = 0;
DVector3 add{};
if (sc.StartBraces(&blockend)) return false;
while (!sc.FoundEndBrace(blockend))
{
sc.MustGetString();
if (sc.Compare("tile")) { sc.GetNumber(starttile, true); endtile = starttile; }
else if (sc.Compare("tile0")) sc.GetNumber(starttile, true);
else if (sc.Compare("tile1")) sc.GetNumber(endtile, true);
else if (sc.Compare("xadd")) sc.GetFloat(add.X, true);
else if (sc.Compare("yadd")) sc.GetFloat(add.Y, true);
else if (sc.Compare("zadd")) sc.GetFloat(add.Z, true);
else if (sc.Compare("angadd")) sc.GetNumber(angadd, true);
else if (sc.Compare("fov")) sc.GetNumber(fov, true);
else if (sc.Compare("hide")) flags |= HUDFLAG_HIDE;
else if (sc.Compare("nobob")) flags |= HUDFLAG_NOBOB;
else if (sc.Compare("flipped")) flags |= HUDFLAG_FLIPPED;
else if (sc.Compare("nodepth")) flags |= HUDFLAG_NODEPTH;
}
if (!ValidateTileRange("hud", starttile, endtile, pos)) return false;
for (int i = starttile; i <= endtile; i++)
{
vec3f_t addf = { (float)add.X, (float)add.Y, (float)add.Z };
int res = md_definehud(mdglobal.lastmodelid, i, addf, angadd, flags, fov);
if (res < 0)
{
if (res == -2) pos.Message(MSG_ERROR, "Invalid tile number %d", i);
return false;
}
}
return true;
}
void parseModel(FScanner& sc, FScriptPosition& pos)
{
FScanner::SavedPos blockend;
FString modelfn;
double scale = 1.0, mzadd = 0.0, myoffset = 0.0;
int32_t shadeoffs = 0, pal = 0, flags = 0;
FixedBitArray<1024> usedframes;
usedframes.Zero();
mdglobal.modelskin = mdglobal.lastmodelskin = 0;
mdglobal.seenframe = 0;
if (!sc.GetString(modelfn)) return;
if (sc.StartBraces(&blockend)) return;
mdglobal.lastmodelid = md_loadmodel(modelfn);
if (mdglobal.lastmodelid < 0)
{
pos.Message(MSG_WARNING, "Unable to load model file \"%s\"\n", modelfn.GetChars());
sc.RestorePos(blockend);
sc.CheckString("}");
return;
}
bool ok = true;
while (!sc.FoundEndBrace(blockend))
{
sc.MustGetString();
if (sc.Compare("scale")) sc.GetFloat(scale, true);
else if (sc.Compare("shade")) sc.GetNumber(shadeoffs, true);
else if (sc.Compare("zadd")) sc.GetFloat(mzadd, true);
else if (sc.Compare("yoffset")) sc.GetFloat(myoffset, true);
else if (sc.Compare("frame")) ok &= parseModelFrameBlock(sc, usedframes);
else if (sc.Compare("anim")) ok &= parseModelAnimBlock(sc);
else if (sc.Compare("skin")) ok &= parseModelSkinBlock(sc, 0);
else if (sc.Compare("detail")) ok &= parseModelSkinBlock(sc, DETAILPAL);
else if (sc.Compare("glow")) ok &= parseModelSkinBlock(sc, GLOWPAL);
else if (sc.Compare("specular")) ok &= parseModelSkinBlock(sc, SPECULARPAL);
else if (sc.Compare("normal")) ok &= parseModelSkinBlock(sc, NORMALPAL);
else if (sc.Compare("hud")) ok &= parseModelHudBlock(sc);
else if (sc.Compare("flags")) sc.GetNumber(flags, true);
}
if (!ok)
{
if (mdglobal.lastmodelid >= 0)
{
pos.Message(MSG_ERROR, "Removing model %d due to errors.", mdglobal.lastmodelid);
md_undefinemodel(mdglobal.lastmodelid);
nextmodelid--;
}
}
else
{
md_setmisc(mdglobal.lastmodelid, (float)scale, shadeoffs, (float)mzadd, (float)myoffset, flags);
mdglobal.modelskin = mdglobal.lastmodelskin = 0;
mdglobal.seenframe = 0;
}
}