mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-25 13:41:05 +00:00
Merge remote-tracking branch 'gzdoom/master' into asmjit
This commit is contained in:
commit
55955b9c22
36 changed files with 1227 additions and 482 deletions
|
@ -1154,6 +1154,7 @@ set (PCH_SOURCES
|
|||
r_data/models/models_md2.cpp
|
||||
r_data/models/models_voxel.cpp
|
||||
r_data/models/models_ue1.cpp
|
||||
r_data/models/models_obj.cpp
|
||||
scripting/symbols.cpp
|
||||
scripting/types.cpp
|
||||
scripting/thingdef.cpp
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include "doomtype.h"
|
||||
#include "configfile.h"
|
||||
#include "files.h"
|
||||
#include "m_random.h"
|
||||
|
||||
#define READBUFFERSIZE 256
|
||||
|
@ -601,17 +602,16 @@ FConfigFile::FConfigEntry *FConfigFile::NewConfigEntry (
|
|||
|
||||
void FConfigFile::LoadConfigFile ()
|
||||
{
|
||||
FILE *file = fopen (PathName, "r");
|
||||
FileReader file;
|
||||
bool succ;
|
||||
|
||||
FileExisted = false;
|
||||
if (file == NULL)
|
||||
if (!file.OpenFile (PathName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
succ = ReadConfig (file);
|
||||
fclose (file);
|
||||
succ = ReadConfig (&file);
|
||||
FileExisted = succ;
|
||||
}
|
||||
|
||||
|
@ -787,7 +787,7 @@ FConfigFile::FConfigEntry *FConfigFile::ReadMultiLineValue(void *file, FConfigSe
|
|||
|
||||
char *FConfigFile::ReadLine (char *string, int n, void *file) const
|
||||
{
|
||||
return fgets (string, n, (FILE *)file);
|
||||
return ((FileReader *)file)->Gets (string, n);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
|
@ -805,7 +805,7 @@ bool FConfigFile::WriteConfigFile () const
|
|||
return true;
|
||||
}
|
||||
|
||||
FILE *file = fopen (PathName, "w");
|
||||
FileWriter *file = FileWriter::Open (PathName);
|
||||
FConfigSection *section;
|
||||
FConfigEntry *entry;
|
||||
|
||||
|
@ -820,27 +820,27 @@ bool FConfigFile::WriteConfigFile () const
|
|||
entry = section->RootEntry;
|
||||
if (section->Note.IsNotEmpty())
|
||||
{
|
||||
fputs (section->Note.GetChars(), file);
|
||||
file->Write (section->Note.GetChars(), section->Note.Len());
|
||||
}
|
||||
fprintf (file, "[%s]\n", section->SectionName.GetChars());
|
||||
file->Printf ("[%s]\n", section->SectionName.GetChars());
|
||||
while (entry != NULL)
|
||||
{
|
||||
if (strpbrk(entry->Value, "\r\n") == NULL)
|
||||
{ // Single-line value
|
||||
fprintf (file, "%s=%s\n", entry->Key, entry->Value);
|
||||
file->Printf ("%s=%s\n", entry->Key, entry->Value);
|
||||
}
|
||||
else
|
||||
{ // Multi-line value
|
||||
const char *endtag = GenerateEndTag(entry->Value);
|
||||
fprintf (file, "%s=<<<%s\n%s\n>>>%s\n", entry->Key,
|
||||
file->Printf ("%s=<<<%s\n%s\n>>>%s\n", entry->Key,
|
||||
endtag, entry->Value, endtag);
|
||||
}
|
||||
entry = entry->Next;
|
||||
}
|
||||
section = section->Next;
|
||||
fputs ("\n", file);
|
||||
file->Write ("\n", 1);
|
||||
}
|
||||
fclose (file);
|
||||
delete file;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -890,7 +890,7 @@ const char *FConfigFile::GenerateEndTag(const char *value)
|
|||
//
|
||||
//====================================================================
|
||||
|
||||
void FConfigFile::WriteCommentHeader (FILE *file) const
|
||||
void FConfigFile::WriteCommentHeader (FileWriter *file) const
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#define __CONFIGFILE_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include "files.h"
|
||||
#include "zstring.h"
|
||||
|
||||
class FConfigFile
|
||||
|
@ -73,7 +74,7 @@ public:
|
|||
bool WriteConfigFile () const;
|
||||
|
||||
protected:
|
||||
virtual void WriteCommentHeader (FILE *file) const;
|
||||
virtual void WriteCommentHeader (FileWriter *file) const;
|
||||
|
||||
virtual char *ReadLine (char *string, int n, void *file) const;
|
||||
bool ReadConfig (void *file);
|
||||
|
|
|
@ -468,7 +468,7 @@ public:
|
|||
TObjPtr<AActor*> MUSINFOactor = nullptr; // For MUSINFO purposes
|
||||
int8_t MUSINFOtics = 0;
|
||||
|
||||
bool settings_controller = false; // Player can control game settings.
|
||||
bool settings_controller = true; // Player can control game settings.
|
||||
int8_t crouching = 0;
|
||||
int8_t crouchdir = 0;
|
||||
|
||||
|
|
17
src/dobjgc.h
17
src/dobjgc.h
|
@ -167,22 +167,19 @@ class TObjPtr
|
|||
DObject *o;
|
||||
};
|
||||
public:
|
||||
TObjPtr() throw()
|
||||
{
|
||||
}
|
||||
TObjPtr() = default;
|
||||
TObjPtr(const TObjPtr<T> &q) = default;
|
||||
|
||||
TObjPtr(T q) throw()
|
||||
: pp(q)
|
||||
{
|
||||
}
|
||||
TObjPtr(const TObjPtr<T> &q) throw()
|
||||
: pp(q.pp)
|
||||
T operator=(T q)
|
||||
{
|
||||
pp = q;
|
||||
return *this;
|
||||
}
|
||||
T operator=(T q) throw()
|
||||
{
|
||||
return pp = q;
|
||||
// The caller must now perform a write barrier.
|
||||
}
|
||||
|
||||
operator T() throw()
|
||||
{
|
||||
return GC::ReadBarrier(pp);
|
||||
|
|
|
@ -103,7 +103,7 @@ enum
|
|||
|
||||
struct PalEntry
|
||||
{
|
||||
PalEntry () {}
|
||||
PalEntry() = default;
|
||||
PalEntry (uint32_t argb) { d = argb; }
|
||||
operator uint32_t () const { return d; }
|
||||
void SetRGB(PalEntry other)
|
||||
|
@ -146,6 +146,7 @@ struct PalEntry
|
|||
{
|
||||
return (d & 0xffffff) == 0xffffff;
|
||||
}
|
||||
PalEntry &operator= (const PalEntry &other) = default;
|
||||
PalEntry &operator= (uint32_t other) { d = other; return *this; }
|
||||
PalEntry InverseColor() const { PalEntry nc; nc.a = a; nc.r = 255 - r; nc.g = 255 - g; nc.b = 255 - b; return nc; }
|
||||
#ifdef __BIG_ENDIAN__
|
||||
|
@ -205,7 +206,7 @@ class FTextureID
|
|||
friend void R_InitSpriteDefs();
|
||||
|
||||
public:
|
||||
FTextureID() throw() {}
|
||||
FTextureID() = default;
|
||||
bool isNull() const { return texnum == 0; }
|
||||
bool isValid() const { return texnum > 0; }
|
||||
bool Exists() const { return texnum >= 0; }
|
||||
|
|
|
@ -167,9 +167,9 @@ FGameConfigFile::~FGameConfigFile ()
|
|||
{
|
||||
}
|
||||
|
||||
void FGameConfigFile::WriteCommentHeader (FILE *file) const
|
||||
void FGameConfigFile::WriteCommentHeader (FileWriter *file) const
|
||||
{
|
||||
fprintf (file, "# This file was generated by " GAMENAME " %s on %s\n", GetVersionString(), myasctime());
|
||||
file->Printf ("# This file was generated by " GAMENAME " %s on %s\n", GetVersionString(), myasctime());
|
||||
}
|
||||
|
||||
void FGameConfigFile::DoAutoloadSetup (FIWadManager *iwad_man)
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
void ReadNetVars ();
|
||||
|
||||
protected:
|
||||
void WriteCommentHeader (FILE *file) const;
|
||||
void WriteCommentHeader (FileWriter *file) const;
|
||||
void CreateStandardAutoExec (const char *section, bool start);
|
||||
|
||||
private:
|
||||
|
|
|
@ -399,7 +399,6 @@ void GLHorizonPortal::DrawContents(HWDrawInfo *hwdi)
|
|||
Clocker c(PortalAll);
|
||||
|
||||
FMaterial * gltexture;
|
||||
PalEntry color;
|
||||
player_t * player=&players[consoleplayer];
|
||||
GLSectorPlane * sp = &origin->plane;
|
||||
auto &vp = di->Viewpoint;
|
||||
|
|
|
@ -228,7 +228,6 @@ int LevelAABBTree::GenerateTreeNode(int *lines, int num_lines, const FVector2 *c
|
|||
// Try sort at longest axis, then if that fails then the other one.
|
||||
// We place the sorted lines into work_buffer and then move the result back to the lines list when done.
|
||||
int left_count, right_count;
|
||||
FVector2 axis;
|
||||
for (int attempt = 0; attempt < 2; attempt++)
|
||||
{
|
||||
// Find the sort plane for axis
|
||||
|
|
|
@ -319,7 +319,6 @@ void FMaterial::SetSpriteRect()
|
|||
|
||||
bool FMaterial::TrimBorders(uint16_t *rect)
|
||||
{
|
||||
PalEntry col;
|
||||
int w;
|
||||
int h;
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class FString;
|
|||
class FName
|
||||
{
|
||||
public:
|
||||
FName() = default;// : Index(0) {}
|
||||
FName() = default;
|
||||
FName (const char *text) { Index = NameData.FindName (text, false); }
|
||||
FName (const char *text, bool noCreate) { Index = NameData.FindName (text, noCreate); }
|
||||
FName (const char *text, size_t textlen, bool noCreate) { Index = NameData.FindName (text, textlen, noCreate); }
|
||||
|
@ -63,7 +63,7 @@ public:
|
|||
|
||||
FName &operator = (const char *text) { Index = NameData.FindName (text, false); return *this; }
|
||||
FName &operator = (const FString &text);
|
||||
FName &operator = (const FName &other) { Index = other.Index; return *this; }
|
||||
FName &operator = (const FName &other) = default;
|
||||
FName &operator = (ENamedName index) { Index = index; return *this; }
|
||||
|
||||
int SetName (const char *text, bool noCreate=false) { return Index = NameData.FindName (text, noCreate); }
|
||||
|
|
|
@ -2345,7 +2345,6 @@ double P_XYMovement (AActor *mo, DVector2 scroll)
|
|||
{
|
||||
static int pushtime = 0;
|
||||
bool bForceSlide = !scroll.isZero();
|
||||
DAngle Angle;
|
||||
DVector2 ptry;
|
||||
player_t *player;
|
||||
DVector2 move;
|
||||
|
|
|
@ -306,7 +306,7 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt,
|
|||
{
|
||||
if (sec.Lines.Size() != 3) continue; // only works with triangular sectors
|
||||
|
||||
DVector3 vt1, vt2, vt3, cross;
|
||||
DVector3 vt1, vt2, vt3;
|
||||
DVector3 vec1, vec2;
|
||||
int vi1, vi2, vi3;
|
||||
|
||||
|
|
|
@ -153,13 +153,13 @@ static struct SteamAppInfo
|
|||
const int AppID;
|
||||
} AppInfo[] =
|
||||
{
|
||||
/*{"doom 2/base", 2300},
|
||||
{"final doom/base", 2290},
|
||||
{"heretic shadow of the serpent riders/base", 2390},
|
||||
{"hexen/base", 2360},
|
||||
{"hexen deathkings of the dark citadel/base", 2370},
|
||||
{"ultimate doom/base", 2280},
|
||||
{"DOOM 3 BFG Edition/base/wads", 208200},*/
|
||||
{"Doom 2/base", 2300},
|
||||
{"Final Doom/base", 2290},
|
||||
{"Heretic Shadow of the Serpent Riders/base", 2390},
|
||||
{"Hexen/base", 2360},
|
||||
{"Hexen Deathkings of the Dark Citadel/base", 2370},
|
||||
{"Ultimate Doom/base", 2280},
|
||||
{"DOOM 3 BFG Edition/base/wads", 208200},
|
||||
{"Strife", 317040}
|
||||
};
|
||||
|
||||
|
@ -190,7 +190,13 @@ TArray<FString> I_GetSteamPath()
|
|||
if(home != NULL && *home != '\0')
|
||||
{
|
||||
FString regPath;
|
||||
regPath.Format("%s/.local/share/Steam/config/config.vdf", home);
|
||||
regPath.Format("%s/.steam/config/config.vdf", home);
|
||||
// [BL] The config seems to have moved from the more modern .local to
|
||||
// .steam at some point. Not sure if it's just my setup so I guess we
|
||||
// can fall back on it?
|
||||
if(!FileExists(regPath))
|
||||
regPath.Format("%s/.local/share/Steam/config/config.vdf", home);
|
||||
|
||||
try
|
||||
{
|
||||
SteamInstallFolders = ParseSteamRegistry(regPath);
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "r_utility.h"
|
||||
#include "r_data/models/models.h"
|
||||
#include "r_data/models/models_ue1.h"
|
||||
#include "r_data/models/models_obj.h"
|
||||
#include "i_time.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -419,7 +420,7 @@ static unsigned FindModel(const char * path, const char * modelfile)
|
|||
FMemLump lumpd = Wads.ReadLump(lump);
|
||||
char * buffer = (char*)lumpd.GetMem();
|
||||
|
||||
if ( (size_t)fullname.IndexOf("_d.3d") == fullname.Len()-5 )
|
||||
if ( (size_t)fullname.LastIndexOf("_d.3d") == fullname.Len()-5 )
|
||||
{
|
||||
FString anivfile = fullname.GetChars();
|
||||
anivfile.Substitute("_d.3d","_a.3d");
|
||||
|
@ -428,7 +429,7 @@ static unsigned FindModel(const char * path, const char * modelfile)
|
|||
model = new FUE1Model;
|
||||
}
|
||||
}
|
||||
else if ( (size_t)fullname.IndexOf("_a.3d") == fullname.Len()-5 )
|
||||
else if ( (size_t)fullname.LastIndexOf("_a.3d") == fullname.Len()-5 )
|
||||
{
|
||||
FString datafile = fullname.GetChars();
|
||||
datafile.Substitute("_a.3d","_d.3d");
|
||||
|
@ -437,6 +438,10 @@ static unsigned FindModel(const char * path, const char * modelfile)
|
|||
model = new FUE1Model;
|
||||
}
|
||||
}
|
||||
else if ( (size_t)fullname.LastIndexOf(".obj") == fullname.Len() - 4 )
|
||||
{
|
||||
model = new FOBJModel;
|
||||
}
|
||||
else if (!memcmp(buffer, "DMDM", 4))
|
||||
{
|
||||
model = new FDMDModel;
|
||||
|
|
588
src/r_data/models/models_obj.cpp
Normal file
588
src/r_data/models/models_obj.cpp
Normal file
|
@ -0,0 +1,588 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2018 Kevin Caccamo
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#include "w_wad.h"
|
||||
#include "r_data/models/models_obj.h"
|
||||
|
||||
/**
|
||||
* Load an OBJ model
|
||||
*
|
||||
* @param fn The path to the model file
|
||||
* @param lumpnum The lump index in the wad collection
|
||||
* @param buffer The contents of the model file
|
||||
* @param length The size of the model file
|
||||
* @return Whether or not the model was parsed successfully
|
||||
*/
|
||||
bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length)
|
||||
{
|
||||
FString objName = Wads.GetLumpFullPath(lumpnum);
|
||||
FString objBuf(buffer, length);
|
||||
|
||||
// Do some replacements before we parse the OBJ string
|
||||
{
|
||||
// Ensure usemtl statements remain intact
|
||||
TArray<FString> mtlUsages;
|
||||
TArray<long> mtlUsageIdxs;
|
||||
long bpos = 0, nlpos = 0, slashpos = 0;
|
||||
while (1)
|
||||
{
|
||||
bpos = objBuf.IndexOf("\nusemtl", bpos);
|
||||
if (bpos == -1) break;
|
||||
slashpos = objBuf.IndexOf('/', bpos);
|
||||
nlpos = objBuf.IndexOf('\n', ++bpos);
|
||||
if (slashpos > nlpos || slashpos == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (nlpos == -1)
|
||||
{
|
||||
nlpos = objBuf.Len();
|
||||
}
|
||||
FString lineStr(objBuf.GetChars() + bpos, nlpos - bpos);
|
||||
mtlUsages.Push(lineStr);
|
||||
mtlUsageIdxs.Push(bpos);
|
||||
}
|
||||
|
||||
// Replace forward slashes with percent signs so they aren't parsed as line comments
|
||||
objBuf.ReplaceChars('/', *newSideSep);
|
||||
char* wObjBuf = objBuf.LockBuffer();
|
||||
|
||||
// Substitute broken usemtl statements with old ones
|
||||
for (size_t i = 0; i < mtlUsages.Size(); i++)
|
||||
{
|
||||
bpos = mtlUsageIdxs[i];
|
||||
nlpos = objBuf.IndexOf('\n', bpos);
|
||||
if (nlpos == -1)
|
||||
{
|
||||
nlpos = objBuf.Len();
|
||||
}
|
||||
memcpy(wObjBuf + bpos, mtlUsages[i].GetChars(), nlpos - bpos);
|
||||
}
|
||||
|
||||
bpos = 0;
|
||||
// Find each OBJ line comment, and convert each to a C-style line comment
|
||||
while (1)
|
||||
{
|
||||
bpos = objBuf.IndexOf('#', bpos);
|
||||
if (bpos == -1) break;
|
||||
if (objBuf[(unsigned int)bpos + 1] == '\n')
|
||||
{
|
||||
wObjBuf[bpos] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
wObjBuf[bpos] = '/';
|
||||
wObjBuf[bpos+1] = '/';
|
||||
}
|
||||
bpos += 1;
|
||||
}
|
||||
wObjBuf = nullptr;
|
||||
objBuf.UnlockBuffer();
|
||||
}
|
||||
sc.OpenString(objName, objBuf);
|
||||
|
||||
FTextureID curMtl = FNullTextureID();
|
||||
OBJSurface *curSurface = nullptr;
|
||||
int aggSurfFaceCount = 0;
|
||||
int curSurfFaceCount = 0;
|
||||
|
||||
while(sc.GetString())
|
||||
{
|
||||
if (sc.Compare("v")) // Vertex
|
||||
{
|
||||
ParseVector<FVector3, 3>(this->verts);
|
||||
}
|
||||
else if (sc.Compare("vn")) // Vertex normal
|
||||
{
|
||||
ParseVector<FVector3, 3>(this->norms);
|
||||
}
|
||||
else if (sc.Compare("vt")) // UV Coordinates
|
||||
{
|
||||
ParseVector<FVector2, 2>(this->uvs);
|
||||
}
|
||||
else if (sc.Compare("usemtl"))
|
||||
{
|
||||
// Get material name and try to load it
|
||||
sc.MustGetString();
|
||||
|
||||
curMtl = LoadSkin("", sc.String);
|
||||
if (!curMtl.isValid())
|
||||
{
|
||||
// Relative to model file path?
|
||||
curMtl = LoadSkin(fn, sc.String);
|
||||
}
|
||||
|
||||
if (!curMtl.isValid())
|
||||
{
|
||||
sc.ScriptMessage("Material %s (#%u) not found.", sc.String, surfaces.Size());
|
||||
}
|
||||
|
||||
// Build surface...
|
||||
if (curSurface == nullptr)
|
||||
{
|
||||
// First surface
|
||||
curSurface = new OBJSurface(curMtl);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (curSurfFaceCount > 0)
|
||||
{
|
||||
// Add previous surface
|
||||
curSurface->numFaces = curSurfFaceCount;
|
||||
curSurface->faceStart = aggSurfFaceCount;
|
||||
surfaces.Push(*curSurface);
|
||||
delete curSurface;
|
||||
// Go to next surface
|
||||
curSurface = new OBJSurface(curMtl);
|
||||
aggSurfFaceCount += curSurfFaceCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
curSurface->skin = curMtl;
|
||||
}
|
||||
}
|
||||
curSurfFaceCount = 0;
|
||||
}
|
||||
else if (sc.Compare("f"))
|
||||
{
|
||||
FString sides[4];
|
||||
OBJFace face;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
// A face must have at least 3 sides
|
||||
sc.MustGetString();
|
||||
sides[i] = sc.String;
|
||||
if (!ParseFaceSide(sides[i], face, i)) return false;
|
||||
}
|
||||
face.sideCount = 3;
|
||||
if (sc.GetString())
|
||||
{
|
||||
if (!sc.Compare("f") && FString(sc.String).IndexOfAny("-0123456789") == 0)
|
||||
{
|
||||
sides[3] = sc.String;
|
||||
face.sideCount += 1;
|
||||
if (!ParseFaceSide(sides[3], face, 3)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.UnGet(); // No 4th side, move back
|
||||
}
|
||||
}
|
||||
faces.Push(face);
|
||||
curSurfFaceCount += 1;
|
||||
}
|
||||
}
|
||||
sc.Close();
|
||||
|
||||
if (curSurface == nullptr)
|
||||
{ // No valid materials detected
|
||||
FTextureID dummyMtl = LoadSkin("", "-NOFLAT-"); // Built-in to GZDoom
|
||||
curSurface = new OBJSurface(dummyMtl);
|
||||
}
|
||||
curSurface->numFaces = curSurfFaceCount;
|
||||
curSurface->faceStart = aggSurfFaceCount;
|
||||
surfaces.Push(*curSurface);
|
||||
delete curSurface;
|
||||
|
||||
if (uvs.Size() == 0)
|
||||
{ // Needed so that OBJs without UVs can work
|
||||
uvs.Push(FVector2(0.0, 0.0));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an x-Dimensional vector
|
||||
*
|
||||
* @tparam T A subclass of TVector2 to be used
|
||||
* @tparam L The length of the vector to parse
|
||||
* @param[out] array The array to append the parsed vector to
|
||||
*/
|
||||
template<typename T, size_t L> void FOBJModel::ParseVector(TArray<T> &array)
|
||||
{
|
||||
float *coord = new float[L];
|
||||
for (size_t axis = 0; axis < L; axis++)
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
coord[axis] = (float)sc.Float;
|
||||
}
|
||||
T vec(coord);
|
||||
array.Push(vec);
|
||||
delete[] coord;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a side of a face
|
||||
*
|
||||
* @param[in] sideStr The side definition string
|
||||
* @param[out] face The face to assign the parsed side data to
|
||||
* @param sidx The 0-based index of the side
|
||||
* @return Whether or not the face side was parsed successfully
|
||||
*/
|
||||
bool FOBJModel::ParseFaceSide(const FString &sideStr, OBJFace &face, int sidx)
|
||||
{
|
||||
OBJFaceSide side;
|
||||
int origIdx;
|
||||
if (sideStr.IndexOf(newSideSep) >= 0)
|
||||
{
|
||||
TArray<FString> sides = sideStr.Split(newSideSep, FString::TOK_KEEPEMPTY);
|
||||
|
||||
if (sides[0].Len() > 0)
|
||||
{
|
||||
origIdx = atoi(sides[0].GetChars());
|
||||
side.vertref = ResolveIndex(origIdx, FaceElement::VertexIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("Vertex reference is not optional!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sides[1].Len() > 0)
|
||||
{
|
||||
origIdx = atoi(sides[1].GetChars());
|
||||
side.uvref = ResolveIndex(origIdx, FaceElement::UVIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
side.uvref = -1;
|
||||
}
|
||||
|
||||
if (sides.Size() > 2)
|
||||
{
|
||||
if (sides[2].Len() > 0)
|
||||
{
|
||||
origIdx = atoi(sides[2].GetChars());
|
||||
side.normref = ResolveIndex(origIdx, FaceElement::VNormalIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
side.normref = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
side.normref = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
origIdx = atoi(sideStr.GetChars());
|
||||
side.vertref = ResolveIndex(origIdx, FaceElement::VertexIndex);
|
||||
side.normref = -1;
|
||||
side.uvref = -1;
|
||||
}
|
||||
face.sides[sidx] = side;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an OBJ index to an absolute index
|
||||
*
|
||||
* OBJ indices are 1-based, and can also be negative
|
||||
*
|
||||
* @param origIndex The original OBJ index to resolve
|
||||
* @param el What type of element the index references
|
||||
* @return The absolute index of the element
|
||||
*/
|
||||
int FOBJModel::ResolveIndex(int origIndex, FaceElement el)
|
||||
{
|
||||
if (origIndex > 0)
|
||||
{
|
||||
return origIndex - 1; // OBJ indices start at 1
|
||||
}
|
||||
else if (origIndex < 0)
|
||||
{
|
||||
if (el == FaceElement::VertexIndex)
|
||||
{
|
||||
return verts.Size() + origIndex; // origIndex is negative
|
||||
}
|
||||
else if (el == FaceElement::UVIndex)
|
||||
{
|
||||
return uvs.Size() + origIndex;
|
||||
}
|
||||
else if (el == FaceElement::VNormalIndex)
|
||||
{
|
||||
return norms.Size() + origIndex;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the vertex buffer for this model
|
||||
*
|
||||
* @param renderer A pointer to the model renderer. Used to allocate the vertex buffer.
|
||||
*/
|
||||
void FOBJModel::BuildVertexBuffer(FModelRenderer *renderer)
|
||||
{
|
||||
if (GetVertexBuffer(renderer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int vbufsize = 0;
|
||||
|
||||
for (size_t i = 0; i < surfaces.Size(); i++)
|
||||
{
|
||||
ConstructSurfaceTris(surfaces[i]);
|
||||
surfaces[i].vbStart = vbufsize;
|
||||
vbufsize += surfaces[i].numTris * 3;
|
||||
}
|
||||
|
||||
auto vbuf = renderer->CreateVertexBuffer(false,true);
|
||||
SetVertexBuffer(renderer, vbuf);
|
||||
|
||||
FModelVertex *vertptr = vbuf->LockVertexBuffer(vbufsize);
|
||||
|
||||
for (size_t i = 0; i < surfaces.Size(); i++)
|
||||
{
|
||||
for (size_t j = 0; j < surfaces[i].numTris; j++)
|
||||
{
|
||||
for (size_t side = 0; side < 3; side++)
|
||||
{
|
||||
FModelVertex *mdv = vertptr +
|
||||
side + j * 3 + // Current surface and previous triangles
|
||||
surfaces[i].vbStart; // Previous surfaces
|
||||
|
||||
OBJFaceSide &curSide = surfaces[i].tris[j].sides[side];
|
||||
|
||||
int vidx = curSide.vertref;
|
||||
int uvidx = (curSide.uvref >= 0 && (unsigned int)curSide.uvref < uvs.Size()) ? curSide.uvref : 0;
|
||||
int nidx = curSide.normref;
|
||||
|
||||
FVector3 curVvec = RealignVector(verts[vidx]);
|
||||
FVector2 curUvec = FixUV(uvs[uvidx]);
|
||||
FVector3 *nvec = nullptr;
|
||||
|
||||
mdv->Set(curVvec.X, curVvec.Y, curVvec.Z, curUvec.X, curUvec.Y);
|
||||
|
||||
if (nidx >= 0 && (unsigned int)nidx < norms.Size())
|
||||
{
|
||||
nvec = new FVector3(RealignVector(norms[nidx]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal
|
||||
// Find other sides of triangle
|
||||
int nextSidx = side + 2;
|
||||
if (nextSidx >= 3) nextSidx -= 3;
|
||||
|
||||
int lastSidx = side + 1;
|
||||
if (lastSidx >= 3) lastSidx -= 3;
|
||||
|
||||
OBJFaceSide &nextSide = surfaces[i].tris[j].sides[nextSidx];
|
||||
OBJFaceSide &lastSide = surfaces[i].tris[j].sides[lastSidx];
|
||||
|
||||
// Cross-multiply the U-vector and V-vector
|
||||
FVector3 uvec = RealignVector(verts[nextSide.vertref]) - curVvec;
|
||||
FVector3 vvec = RealignVector(verts[lastSide.vertref]) - curVvec;
|
||||
|
||||
nvec = new FVector3(uvec ^ vvec);
|
||||
}
|
||||
mdv->SetNormal(nvec->X, nvec->Y, nvec->Z);
|
||||
delete nvec;
|
||||
}
|
||||
}
|
||||
delete[] surfaces[i].tris;
|
||||
}
|
||||
vbuf->UnlockVertexBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in the triangle data for a surface
|
||||
*
|
||||
* @param[in,out] surf The surface to fill in the triangle data for
|
||||
*/
|
||||
void FOBJModel::ConstructSurfaceTris(OBJSurface &surf)
|
||||
{
|
||||
unsigned int triCount = 0;
|
||||
|
||||
size_t start = surf.faceStart;
|
||||
size_t end = start + surf.numFaces;
|
||||
for (size_t i = start; i < end; i++)
|
||||
{
|
||||
triCount += faces[i].sideCount - 2;
|
||||
}
|
||||
|
||||
surf.numTris = triCount;
|
||||
surf.tris = new OBJFace[triCount];
|
||||
|
||||
for (size_t i = start, triIdx = 0; i < end; i++, triIdx++)
|
||||
{
|
||||
surf.tris[triIdx].sideCount = 3;
|
||||
if (faces[i].sideCount == 3)
|
||||
{
|
||||
memcpy(surf.tris[triIdx].sides, faces[i].sides, sizeof(OBJFaceSide) * 3);
|
||||
}
|
||||
else if (faces[i].sideCount == 4) // Triangulate face
|
||||
{
|
||||
OBJFace *triangulated = new OBJFace[2];
|
||||
TriangulateQuad(faces[i], triangulated);
|
||||
memcpy(surf.tris[triIdx].sides, triangulated[0].sides, sizeof(OBJFaceSide) * 3);
|
||||
memcpy(surf.tris[triIdx+1].sides, triangulated[1].sides, sizeof(OBJFaceSide) * 3);
|
||||
delete[] triangulated;
|
||||
triIdx += 1; // Filling out two faces
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triangulate a 4-sided face
|
||||
*
|
||||
* @param[in] quad The 4-sided face to triangulate
|
||||
* @param[out] tris The resultant triangle data
|
||||
*/
|
||||
void FOBJModel::TriangulateQuad(const OBJFace &quad, OBJFace *tris)
|
||||
{
|
||||
tris[0].sideCount = 3;
|
||||
tris[1].sideCount = 3;
|
||||
|
||||
int tsidx[2][3] = {{0, 1, 3}, {1, 2, 3}};
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
tris[j].sides[i].vertref = quad.sides[tsidx[j][i]].vertref;
|
||||
tris[j].sides[i].uvref = quad.sides[tsidx[j][i]].uvref;
|
||||
tris[j].sides[i].normref = quad.sides[tsidx[j][i]].normref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-align a vector to match MD3 alignment
|
||||
*
|
||||
* @param vecToRealign The vector to re-align
|
||||
* @return The re-aligned vector
|
||||
*/
|
||||
inline FVector3 FOBJModel::RealignVector(FVector3 vecToRealign)
|
||||
{
|
||||
vecToRealign.Z *= -1;
|
||||
return vecToRealign;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix UV coordinates of a UV vector
|
||||
*
|
||||
* @param vecToRealign The vector to fix
|
||||
* @return The fixed UV coordinate vector
|
||||
*/
|
||||
inline FVector2 FOBJModel::FixUV(FVector2 vecToRealign)
|
||||
{
|
||||
vecToRealign.Y *= -1;
|
||||
return vecToRealign;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of the frame with the given name
|
||||
*
|
||||
* OBJ models are not animated, so this always returns 0
|
||||
*
|
||||
* @param name The name of the frame
|
||||
* @return The index of the frame
|
||||
*/
|
||||
int FOBJModel::FindFrame(const char* name)
|
||||
{
|
||||
return 0; // OBJs are not animated.
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the model
|
||||
*
|
||||
* @param renderer The model renderer
|
||||
* @param skin The loaded skin for the surface
|
||||
* @param frameno Unused
|
||||
* @param frameno2 Unused
|
||||
* @param inter Unused
|
||||
* @param translation The translation for the skin
|
||||
*/
|
||||
void FOBJModel::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frameno, int frameno2, double inter, int translation)
|
||||
{
|
||||
for (unsigned int i = 0; i < surfaces.Size(); i++)
|
||||
{
|
||||
OBJSurface *surf = &surfaces[i];
|
||||
|
||||
FTexture *userSkin = skin;
|
||||
if (!userSkin)
|
||||
{
|
||||
if (i < MD3_MAX_SURFACES && curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid())
|
||||
{
|
||||
userSkin = TexMan(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i]);
|
||||
}
|
||||
else if (surf->skin.isValid())
|
||||
{
|
||||
userSkin = TexMan(surf->skin);
|
||||
}
|
||||
}
|
||||
|
||||
// Still no skin after checking for one?
|
||||
if (!userSkin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
renderer->SetMaterial(userSkin, false, translation);
|
||||
GetVertexBuffer(renderer)->SetupFrame(renderer, surf->vbStart, surf->vbStart, surf->numTris * 3);
|
||||
renderer->DrawArrays(0, surf->numTris * 3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-cache skins for the model
|
||||
*
|
||||
* @param hitlist The list of textures
|
||||
*/
|
||||
void FOBJModel::AddSkins(uint8_t* hitlist)
|
||||
{
|
||||
for (size_t i = 0; i < surfaces.Size(); i++)
|
||||
{
|
||||
if (i < MD3_MAX_SURFACES && curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid())
|
||||
{
|
||||
// Precache skins manually reassigned by the user.
|
||||
// On OBJs with lots of skins, such as Doom map OBJs exported from GZDB,
|
||||
// there may be too many skins for the user to manually change, unless
|
||||
// the limit is bumped or surfaceskinIDs is changed to a TArray<FTextureID>.
|
||||
hitlist[curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].GetIndex()] |= FTextureManager::HIT_Flat;
|
||||
return; // No need to precache skin that was replaced
|
||||
}
|
||||
|
||||
OBJSurface * surf = &surfaces[i];
|
||||
if (surf->skin.isValid())
|
||||
{
|
||||
hitlist[surf->skin.GetIndex()] |= FTextureManager::HIT_Flat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the data that was loaded
|
||||
*/
|
||||
FOBJModel::~FOBJModel()
|
||||
{
|
||||
verts.Clear();
|
||||
norms.Clear();
|
||||
uvs.Clear();
|
||||
faces.Clear();
|
||||
surfaces.Clear();
|
||||
}
|
87
src/r_data/models/models_obj.h
Normal file
87
src/r_data/models/models_obj.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2018 Kevin Caccamo
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#ifndef __GL_MODELS_OBJ_H__
|
||||
#define __GL_MODELS_OBJ_H__
|
||||
|
||||
#include "models.h"
|
||||
#include "sc_man.h"
|
||||
|
||||
class FOBJModel : public FModel
|
||||
{
|
||||
private:
|
||||
const char *newSideSep = "$"; // OBJ side separator is /, which is parsed as a line comment by FScanner if two of them are next to each other.
|
||||
|
||||
enum class FaceElement
|
||||
{
|
||||
VertexIndex,
|
||||
UVIndex,
|
||||
VNormalIndex
|
||||
};
|
||||
|
||||
struct OBJFaceSide
|
||||
{
|
||||
int vertref;
|
||||
int normref;
|
||||
int uvref;
|
||||
};
|
||||
struct OBJFace
|
||||
{
|
||||
unsigned int sideCount;
|
||||
OBJFaceSide sides[4];
|
||||
};
|
||||
struct OBJSurface // 1 surface per 'usemtl'
|
||||
{
|
||||
unsigned int numTris; // Number of triangulated faces
|
||||
unsigned int numFaces; // Number of faces
|
||||
unsigned int vbStart; // First index in vertex buffer
|
||||
unsigned int faceStart; // Index of first face in faces array
|
||||
OBJFace* tris; // Triangles
|
||||
FTextureID skin;
|
||||
OBJSurface(FTextureID skin): numTris(0), numFaces(0), vbStart(0), faceStart(0), tris(nullptr), skin(skin) {}
|
||||
};
|
||||
|
||||
TArray<FVector3> verts;
|
||||
TArray<FVector3> norms;
|
||||
TArray<FVector2> uvs;
|
||||
TArray<OBJFace> faces;
|
||||
TArray<OBJSurface> surfaces;
|
||||
FScanner sc;
|
||||
|
||||
template<typename T, size_t L> void ParseVector(TArray<T> &array);
|
||||
bool ParseFaceSide(const FString &side, OBJFace &face, int sidx);
|
||||
void ConstructSurfaceTris(OBJSurface &surf);
|
||||
int ResolveIndex(int origIndex, FaceElement el);
|
||||
void TriangulateQuad(const OBJFace &quad, OBJFace *tris);
|
||||
FVector3 RealignVector(FVector3 vecToRealign);
|
||||
FVector2 FixUV(FVector2 vecToRealign);
|
||||
public:
|
||||
FOBJModel() {}
|
||||
~FOBJModel();
|
||||
bool Load(const char* fn, int lumpnum, const char* buffer, int length) override;
|
||||
int FindFrame(const char* name) override;
|
||||
void RenderFrame(FModelRenderer* renderer, FTexture* skin, int frame, int frame2, double inter, int translation=0) override;
|
||||
void BuildVertexBuffer(FModelRenderer* renderer) override;
|
||||
void AddSkins(uint8_t* hitlist) override;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -776,8 +776,8 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector,
|
|||
{
|
||||
DVector2 disp = level.Displacements.getOffset(pgroup, poly->CenterSubsector->sector->PortalGroup);
|
||||
CalcPolyobjSoundOrg(listenpos + disp, poly, *pos);
|
||||
pos->X += (float)disp.X;
|
||||
pos->Z += (float)disp.Y;
|
||||
pos->X -= (float)disp.X;
|
||||
pos->Z -= (float)disp.Y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -114,15 +114,8 @@ public:
|
|||
{
|
||||
ID = S_FindSound(name.GetChars());
|
||||
}
|
||||
FSoundID(const FSoundID &other)
|
||||
{
|
||||
ID = other.ID;
|
||||
}
|
||||
FSoundID &operator=(const FSoundID &other)
|
||||
{
|
||||
ID = other.ID;
|
||||
return *this;
|
||||
}
|
||||
FSoundID(const FSoundID &other) = default;
|
||||
FSoundID &operator=(const FSoundID &other) = default;
|
||||
FSoundID &operator=(const char *name)
|
||||
{
|
||||
ID = S_FindSound(name);
|
||||
|
@ -168,19 +161,7 @@ class FSoundIDNoInit : public FSoundID
|
|||
{
|
||||
public:
|
||||
FSoundIDNoInit() : FSoundID(NoInit) {}
|
||||
|
||||
FSoundID &operator=(const FSoundID &other)
|
||||
{
|
||||
return FSoundID::operator=(other);
|
||||
}
|
||||
FSoundID &operator=(const char *name)
|
||||
{
|
||||
return FSoundID::operator=(name);
|
||||
}
|
||||
FSoundID &operator=(const FString &name)
|
||||
{
|
||||
return FSoundID::operator=(name);
|
||||
}
|
||||
using FSoundID::operator=;
|
||||
};
|
||||
|
||||
extern FRolloffInfo S_Rolloff;
|
||||
|
|
|
@ -327,7 +327,7 @@ static FFlagDef ActorFlagDefs[]=
|
|||
DEFINE_FLAG(RF, INVISIBLE, AActor, renderflags),
|
||||
DEFINE_FLAG(RF, FORCEYBILLBOARD, AActor, renderflags),
|
||||
DEFINE_FLAG(RF, FORCEXYBILLBOARD, AActor, renderflags),
|
||||
DEFINE_FLAG(RF, ROLLSPRITE, AActor, renderflags), // [marrub] roll the sprite billboard
|
||||
DEFINE_FLAG(RF, ROLLSPRITE, AActor, renderflags), // [marrub] roll the sprite billboard
|
||||
// [fgsfds] Flat sprites
|
||||
DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags),
|
||||
DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags),
|
||||
|
@ -593,7 +593,7 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2, bo
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// Gets the name of an actor flag
|
||||
// Gets the name of an actor flag
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
@ -1266,6 +1266,14 @@ DEFINE_ACTION_FUNCTION(FStringStruct, IndexOf)
|
|||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FStringStruct, LastIndexOf)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_STRING(substr);
|
||||
PARAM_INT_DEF(endIndex);
|
||||
ACTION_RETURN_INT(self->LastIndexOfBroken(substr, endIndex));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FStringStruct, RightIndexOf)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_STRING(substr);
|
||||
|
|
12
src/stats.h
12
src/stats.h
|
@ -57,12 +57,6 @@ public:
|
|||
class cycle_t
|
||||
{
|
||||
public:
|
||||
cycle_t &operator= (const cycle_t &o)
|
||||
{
|
||||
Sec = o.Sec;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
Sec = 0;
|
||||
|
@ -153,12 +147,6 @@ inline uint64_t rdtsc()
|
|||
class cycle_t
|
||||
{
|
||||
public:
|
||||
cycle_t &operator= (const cycle_t &o)
|
||||
{
|
||||
Counter = o.Counter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
Counter = 0;
|
||||
|
|
|
@ -961,8 +961,6 @@ PalEntry FTexture::averageColor(const uint32_t *data, int size, int maxout)
|
|||
|
||||
PalEntry FTexture::GetSkyCapColor(bool bottom)
|
||||
{
|
||||
PalEntry col;
|
||||
|
||||
if (!bSWSkyColorDone)
|
||||
{
|
||||
bSWSkyColorDone = true;
|
||||
|
|
|
@ -594,6 +594,46 @@ void F2DDrawer::AddLine(int x1, int y1, int x2, int y2, int palcolor, uint32_t c
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::AddThickLine(int x1, int y1, int x2, int y2, double thickness, uint32_t color)
|
||||
{
|
||||
PalEntry p = (PalEntry)color;
|
||||
|
||||
DVector2 point0(x1, y1);
|
||||
DVector2 point1(x2, y2);
|
||||
|
||||
DVector2 delta = point1 - point0;
|
||||
DVector2 perp(-delta.Y, delta.X);
|
||||
perp.MakeUnit();
|
||||
perp *= thickness / 2;
|
||||
|
||||
DVector2 corner0 = point0 + perp;
|
||||
DVector2 corner1 = point0 - perp;
|
||||
DVector2 corner2 = point1 + perp;
|
||||
DVector2 corner3 = point1 - perp;
|
||||
|
||||
RenderCommand dg;
|
||||
|
||||
dg.mType = DrawTypeTriangles;
|
||||
dg.mVertCount = 4;
|
||||
dg.mVertIndex = (int)mVertices.Reserve(4);
|
||||
dg.mRenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
||||
auto ptr = &mVertices[dg.mVertIndex];
|
||||
ptr->Set(corner0.X, corner0.Y, 0, 0, 0, p); ptr++;
|
||||
ptr->Set(corner1.X, corner1.Y, 0, 0, 0, p); ptr++;
|
||||
ptr->Set(corner2.X, corner2.Y, 0, 0, 0, p); ptr++;
|
||||
ptr->Set(corner3.X, corner3.Y, 0, 0, 0, p); ptr++;
|
||||
dg.mIndexIndex = mIndices.Size();
|
||||
dg.mIndexCount += 6;
|
||||
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
|
||||
AddCommand(&dg);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::AddPixel(int x1, int y1, int palcolor, uint32_t color)
|
||||
{
|
||||
PalEntry p = color ? (PalEntry)color : GPalette.BaseColors[palcolor];
|
||||
|
|
|
@ -149,6 +149,7 @@ public:
|
|||
|
||||
|
||||
void AddLine(int x1, int y1, int x2, int y2, int palcolor, uint32_t color);
|
||||
void AddThickLine(int x1, int y1, int x2, int y2, double thickness, uint32_t color);
|
||||
void AddPixel(int x1, int y1, int palcolor, uint32_t color);
|
||||
|
||||
void Clear();
|
||||
|
|
|
@ -1088,6 +1088,24 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawLine)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void DFrameBuffer::DrawThickLine(int x0, int y0, int x1, int y1, double thickness, uint32_t realcolor) {
|
||||
m2DDrawer.AddThickLine(x0, y0, x1, y1, thickness, realcolor);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Screen, DrawThickLine)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(x0);
|
||||
PARAM_INT(y0);
|
||||
PARAM_INT(x1);
|
||||
PARAM_INT(y1);
|
||||
PARAM_FLOAT(thickness);
|
||||
PARAM_INT(color);
|
||||
if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
|
||||
screen->DrawThickLine(x0, y0, x1, y1, thickness, color);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Draw a single pixel
|
||||
|
|
|
@ -1995,7 +1995,14 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l
|
|||
|
||||
FixXMoves();
|
||||
|
||||
if (!noTranslate) LoadTranslations();
|
||||
if (noTranslate)
|
||||
{
|
||||
ActiveColors = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadTranslations();
|
||||
}
|
||||
|
||||
delete[] charlumps;
|
||||
}
|
||||
|
|
|
@ -498,6 +498,9 @@ public:
|
|||
// Draws a line
|
||||
void DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32_t realcolor);
|
||||
|
||||
// Draws a line with thickness
|
||||
void DrawThickLine(int x0, int y0, int x1, int y1, double thickness, uint32_t realcolor);
|
||||
|
||||
// Draws a single pixel
|
||||
void DrawPixel(int x, int y, int palcolor, uint32_t rgbcolor);
|
||||
|
||||
|
|
110
src/vectors.h
110
src/vectors.h
|
@ -66,19 +66,14 @@ struct TVector2
|
|||
{
|
||||
vec_t X, Y;
|
||||
|
||||
TVector2 ()
|
||||
{
|
||||
}
|
||||
TVector2() = default;
|
||||
|
||||
TVector2 (vec_t a, vec_t b)
|
||||
: X(a), Y(b)
|
||||
{
|
||||
}
|
||||
|
||||
TVector2 (const TVector2 &other)
|
||||
: X(other.X), Y(other.Y)
|
||||
{
|
||||
}
|
||||
TVector2(const TVector2 &other) = default;
|
||||
|
||||
TVector2 (const TVector3<vec_t> &other) // Copy the X and Y from the 3D vector and discard the Z
|
||||
: X(other.X), Y(other.Y)
|
||||
|
@ -95,18 +90,7 @@ struct TVector2
|
|||
return X == 0 && Y == 0;
|
||||
}
|
||||
|
||||
TVector2 &operator= (const TVector2 &other)
|
||||
{
|
||||
// This might seem backwards, but this helps produce smaller code when a newly
|
||||
// created vector is assigned, because the components can just be popped off
|
||||
// the FPU stack in order without the need for fxch. For platforms with a
|
||||
// more sensible registered-based FPU, of course, the order doesn't matter.
|
||||
// (And, yes, I know fxch can improve performance in the right circumstances,
|
||||
// but this isn't one of those times. Here, it's little more than a no-op that
|
||||
// makes the exe 2 bytes larger whenever you assign one vector to another.)
|
||||
Y = other.Y, X = other.X;
|
||||
return *this;
|
||||
}
|
||||
TVector2 &operator= (const TVector2 &other) = default;
|
||||
|
||||
// Access X and Y as an array
|
||||
vec_t &operator[] (int index)
|
||||
|
@ -317,9 +301,7 @@ struct TVector3
|
|||
|
||||
vec_t X, Y, Z;
|
||||
|
||||
TVector3 ()
|
||||
{
|
||||
}
|
||||
TVector3() = default;
|
||||
|
||||
TVector3 (vec_t a, vec_t b, vec_t c)
|
||||
: X(a), Y(b), Z(c)
|
||||
|
@ -331,10 +313,7 @@ struct TVector3
|
|||
{
|
||||
}
|
||||
|
||||
TVector3 (const TVector3 &other)
|
||||
: X(other.X), Y(other.Y), Z(other.Z)
|
||||
{
|
||||
}
|
||||
TVector3(const TVector3 &other) = default;
|
||||
|
||||
TVector3 (const Vector2 &xy, vec_t z)
|
||||
: X(xy.X), Y(xy.Y), Z(z)
|
||||
|
@ -353,11 +332,7 @@ struct TVector3
|
|||
return X == 0 && Y == 0 && Z == 0;
|
||||
}
|
||||
|
||||
TVector3 &operator= (const TVector3 &other)
|
||||
{
|
||||
Z = other.Z, Y = other.Y, X = other.X;
|
||||
return *this;
|
||||
}
|
||||
TVector3 &operator= (const TVector3 &other) = default;
|
||||
|
||||
// Access X and Y and Z as an array
|
||||
vec_t &operator[] (int index)
|
||||
|
@ -546,13 +521,12 @@ struct TVector3
|
|||
{
|
||||
right = { 0.f, 0.f, 1.f };
|
||||
}
|
||||
|
||||
if (major == 1 || (major == 2 && n[2] > 0.f))
|
||||
else if (major == 1 || (major == 2 && n[2] > 0.f))
|
||||
{
|
||||
right = { 1.f, 0.f, 0.f };
|
||||
}
|
||||
|
||||
if (major == 2 && n[2] < 0.0f)
|
||||
// Unconditional to ease static analysis
|
||||
else // major == 2 && n[2] <= 0.0f
|
||||
{
|
||||
right = { -1.f, 0.f, 0.f };
|
||||
}
|
||||
|
@ -662,9 +636,7 @@ struct TVector4
|
|||
|
||||
vec_t X, Y, Z, W;
|
||||
|
||||
TVector4()
|
||||
{
|
||||
}
|
||||
TVector4() = default;
|
||||
|
||||
TVector4(vec_t a, vec_t b, vec_t c, vec_t d)
|
||||
: X(a), Y(b), Z(c), W(d)
|
||||
|
@ -676,10 +648,7 @@ struct TVector4
|
|||
{
|
||||
}
|
||||
|
||||
TVector4(const TVector4 &other)
|
||||
: X(other.X), Y(other.Y), Z(other.Z), W(other.W)
|
||||
{
|
||||
}
|
||||
TVector4(const TVector4 &other) = default;
|
||||
|
||||
TVector4(const Vector3 &xyz, vec_t w)
|
||||
: X(xyz.X), Y(xyz.Y), Z(xyz.Z), W(w)
|
||||
|
@ -696,11 +665,7 @@ struct TVector4
|
|||
return X == 0 && Y == 0 && Z == 0 && W == 0;
|
||||
}
|
||||
|
||||
TVector4 &operator= (const TVector4 &other)
|
||||
{
|
||||
W = other.W, Z = other.Z, Y = other.Y, X = other.X;
|
||||
return *this;
|
||||
}
|
||||
TVector4 &operator= (const TVector4 &other) = default;
|
||||
|
||||
// Access X and Y and Z as an array
|
||||
vec_t &operator[] (int index)
|
||||
|
@ -939,16 +904,8 @@ struct TMatrix3x3
|
|||
|
||||
vec_t Cells[3][3];
|
||||
|
||||
TMatrix3x3()
|
||||
{
|
||||
}
|
||||
|
||||
TMatrix3x3(const TMatrix3x3 &other)
|
||||
{
|
||||
(*this)[0] = other[0];
|
||||
(*this)[1] = other[1];
|
||||
(*this)[2] = other[2];
|
||||
}
|
||||
TMatrix3x3() = default;
|
||||
TMatrix3x3(const TMatrix3x3 &other) = default;
|
||||
|
||||
TMatrix3x3(const Vector3 &row1, const Vector3 &row2, const Vector3 &row3)
|
||||
{
|
||||
|
@ -1151,32 +1108,15 @@ struct TAngle
|
|||
TAngle &operator= (long other) = delete;
|
||||
TAngle &operator= (unsigned long other) = delete;
|
||||
|
||||
TAngle ()
|
||||
{
|
||||
}
|
||||
TAngle() = default;
|
||||
|
||||
TAngle (vec_t amt)
|
||||
: Degrees(amt)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
TAngle (int amt)
|
||||
: Degrees(vec_t(amt))
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
TAngle (const TAngle &other)
|
||||
: Degrees(other.Degrees)
|
||||
{
|
||||
}
|
||||
|
||||
TAngle &operator= (const TAngle &other)
|
||||
{
|
||||
Degrees = other.Degrees;
|
||||
return *this;
|
||||
}
|
||||
TAngle(const TAngle &other) = default;
|
||||
TAngle &operator= (const TAngle &other) = default;
|
||||
|
||||
TAngle &operator= (double other)
|
||||
{
|
||||
|
@ -1491,25 +1431,15 @@ struct TRotator
|
|||
Angle Roll; // rotation about the forward axis.
|
||||
Angle CamRoll; // Roll specific to actor cameras. Used by quakes.
|
||||
|
||||
TRotator ()
|
||||
{
|
||||
}
|
||||
TRotator() = default;
|
||||
|
||||
TRotator (const Angle &p, const Angle &y, const Angle &r)
|
||||
: Pitch(p), Yaw(y), Roll(r)
|
||||
{
|
||||
}
|
||||
|
||||
TRotator (const TRotator &other)
|
||||
: Pitch(other.Pitch), Yaw(other.Yaw), Roll(other.Roll)
|
||||
{
|
||||
}
|
||||
|
||||
TRotator &operator= (const TRotator &other)
|
||||
{
|
||||
Roll = other.Roll, Yaw = other.Yaw, Pitch = other.Pitch;
|
||||
return *this;
|
||||
}
|
||||
TRotator(const TRotator &other) = default;
|
||||
TRotator &operator= (const TRotator &other) = default;
|
||||
|
||||
// Access angles as an array
|
||||
Angle &operator[] (int index)
|
||||
|
|
|
@ -55,9 +55,9 @@ const char *GetVersionString();
|
|||
#define RC_FILEVERSION 3,5,9999,0
|
||||
#define RC_PRODUCTVERSION 3,5,9999,0
|
||||
#define RC_PRODUCTVERSION2 VERSIONSTR
|
||||
// These are for content versioning. The current state is '3.5'.
|
||||
// These are for content versioning.
|
||||
#define VER_MAJOR 3
|
||||
#define VER_MINOR 5
|
||||
#define VER_MINOR 6
|
||||
#define VER_REVISION 0
|
||||
|
||||
// Version identifier for network games.
|
||||
|
|
|
@ -507,31 +507,11 @@ long FString::IndexOfAny (const char *charset, long startIndex) const
|
|||
return long(brk - Chars);
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const FString &substr) const
|
||||
{
|
||||
return LastIndexOf (substr.Chars, long(Len()), substr.Len());
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const char *substr) const
|
||||
{
|
||||
return LastIndexOf (substr, long(Len()), strlen(substr));
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (char subchar) const
|
||||
{
|
||||
return LastIndexOf (subchar, long(Len()));
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const FString &substr, long endIndex) const
|
||||
{
|
||||
return LastIndexOf (substr.Chars, endIndex, substr.Len());
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const char *substr, long endIndex) const
|
||||
{
|
||||
return LastIndexOf (substr, endIndex, strlen(substr));
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (char subchar, long endIndex) const
|
||||
{
|
||||
if ((size_t)endIndex > Len())
|
||||
|
@ -548,8 +528,10 @@ long FString::LastIndexOf (char subchar, long endIndex) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const char *substr, long endIndex, size_t substrlen) const
|
||||
long FString::LastIndexOfBroken (const FString &_substr, long endIndex) const
|
||||
{
|
||||
const char *substr = _substr.GetChars();
|
||||
size_t substrlen = _substr.Len();
|
||||
if ((size_t)endIndex > Len())
|
||||
{
|
||||
endIndex = long(Len());
|
||||
|
@ -596,6 +578,43 @@ long FString::LastIndexOfAny (const char *charset, long endIndex) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const FString &substr) const
|
||||
{
|
||||
return LastIndexOf(substr.Chars, long(Len() - substr.Len()), substr.Len());
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const FString &substr, long endIndex) const
|
||||
{
|
||||
return LastIndexOf(substr.Chars, endIndex, substr.Len());
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const char *substr) const
|
||||
{
|
||||
return LastIndexOf(substr, long(Len() - strlen(substr)), strlen(substr));
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const char *substr, long endIndex) const
|
||||
{
|
||||
return LastIndexOf(substr, endIndex, strlen(substr));
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const char *substr, long endIndex, size_t substrlen) const
|
||||
{
|
||||
if ((size_t)endIndex + substrlen > Len())
|
||||
{
|
||||
endIndex = long(Len() - substrlen);
|
||||
}
|
||||
while (endIndex >= 0)
|
||||
{
|
||||
if (strncmp (substr, Chars + endIndex, substrlen) == 0)
|
||||
{
|
||||
return endIndex;
|
||||
}
|
||||
endIndex--;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FString::ToUpper ()
|
||||
{
|
||||
LockBuffer();
|
||||
|
@ -1003,7 +1022,7 @@ void FString::Substitute (const char *oldstr, const char *newstr, size_t oldstrl
|
|||
|
||||
bool FString::IsInt () const
|
||||
{
|
||||
// String must match: [whitespace] [{+ | –}] [0 [{ x | X }]] [digits] [whitespace]
|
||||
// String must match: [whitespace] [{+ | <EFBFBD>}] [0 [{ x | X }]] [digits] [whitespace]
|
||||
|
||||
/* This state machine is based on a simplification of re2c's output for this input:
|
||||
digits = [0-9];
|
||||
|
|
|
@ -201,19 +201,22 @@ public:
|
|||
long IndexOfAny (const FString &charset, long startIndex=0) const;
|
||||
long IndexOfAny (const char *charset, long startIndex=0) const;
|
||||
|
||||
long LastIndexOf (const FString &substr) const;
|
||||
long LastIndexOf (const char *substr) const;
|
||||
// This is only kept for backwards compatibility with old ZScript versions that used this function and depend on its bug.
|
||||
long LastIndexOf (char subchar) const;
|
||||
long LastIndexOf (const FString &substr, long endIndex) const;
|
||||
long LastIndexOf (const char *substr, long endIndex) const;
|
||||
long LastIndexOfBroken (const FString &substr, long endIndex) const;
|
||||
long LastIndexOf (char subchar, long endIndex) const;
|
||||
long LastIndexOf (const char *substr, long endIndex, size_t substrlen) const;
|
||||
|
||||
long LastIndexOfAny (const FString &charset) const;
|
||||
long LastIndexOfAny (const char *charset) const;
|
||||
long LastIndexOfAny (const FString &charset, long endIndex) const;
|
||||
long LastIndexOfAny (const char *charset, long endIndex) const;
|
||||
|
||||
long LastIndexOf (const FString &substr) const;
|
||||
long LastIndexOf (const FString &substr, long endIndex) const;
|
||||
long LastIndexOf (const char *substr) const;
|
||||
long LastIndexOf (const char *substr, long endIndex) const;
|
||||
long LastIndexOf (const char *substr, long endIndex, size_t substrlen) const;
|
||||
|
||||
void ToUpper ();
|
||||
void ToLower ();
|
||||
void SwapCase ();
|
||||
|
@ -463,4 +466,3 @@ template<> struct THashTraits<FString>
|
|||
// Compares two keys, returning zero if they are the same.
|
||||
int Compare(const FString &left, const FString &right) { return left.Compare(right); }
|
||||
};
|
||||
|
||||
|
|
|
@ -2820,6 +2820,8 @@ GLPREFMNU_DITHER = "Dither output";
|
|||
GLPREFMNU_PALTONEMAPORDER = "Tonemap Palette Order";
|
||||
GLPREFMNU_PALTONEMAPPOWER = "Tonemap Palette Exponent";
|
||||
GLPREFMNU_SWLMBANDED = "Banded SW Lightmode";
|
||||
GLPREFMNU_VRIPD = "Distance Between Your Eyes";
|
||||
GLPREFMNU_VRSCREENDIST = "Distance From Your Screen";
|
||||
|
||||
// Option Values
|
||||
OPTVAL_SMART = "Smart";
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2290,6 +2290,8 @@ OptionMenu "OpenGLOptions" protected
|
|||
{
|
||||
Option "$GLPREFMNU_VRQUADSTEREO", vr_enable_quadbuffered, "OnOff"
|
||||
}
|
||||
Slider "$GLPREFMNU_VRIPD", vr_ipd, 0.041, 0.073, 0.001, 3
|
||||
Slider "$GLPREFMNU_VRSCREENDIST", vr_screendist, 0.2, 10.0, 0.1, 1
|
||||
StaticText " "
|
||||
Option "$GLPREFMNU_MULTISAMPLE", gl_multisample, "Multisample"
|
||||
Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes"
|
||||
|
|
|
@ -194,6 +194,7 @@ struct Screen native
|
|||
native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...);
|
||||
native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...);
|
||||
native static void DrawLine(int x0, int y0, int x1, int y1, Color color);
|
||||
native static void DrawThickLine(int x0, int y0, int x1, int y1, double thickness, Color color);
|
||||
native static void DrawFrame(int x, int y, int w, int h);
|
||||
native static Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true);
|
||||
native static double GetAspectRatio();
|
||||
|
@ -815,7 +816,8 @@ struct StringStruct native
|
|||
native int CharCodeAt(int pos) const;
|
||||
native String Filter();
|
||||
native int IndexOf(String substr, int startIndex = 0) const;
|
||||
native int LastIndexOf(String substr, int endIndex = 2147483647) const;
|
||||
deprecated("3.5.1") native int LastIndexOf(String substr, int endIndex = 2147483647) const;
|
||||
native int RightIndexOf(String substr, int endIndex = 2147483647) const;
|
||||
native void ToUpper();
|
||||
native void ToLower();
|
||||
native int ToInt(int base = 0) const;
|
||||
|
|
Loading…
Reference in a new issue