1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-07-07 00:36:00 +02:00

Additional 3d support

This commit is contained in:
Brian Fiete 2021-05-12 07:24:29 -04:00
parent 70680fdf39
commit f26df6c86b
32 changed files with 2370 additions and 165 deletions

View file

@ -339,9 +339,9 @@ void DrawLayer::SetTexture(int texIdx, Texture* texture)
}
}
void DrawLayer::SetShaderConstantDataTyped(int slotIdx, void* constData, int size, int* typeData, int typeCount)
void DrawLayer::SetShaderConstantDataTyped(int usageIdx, int slotIdx, void* constData, int size, int* typeData, int typeCount)
{
SetShaderConstantData(slotIdx, constData, size);
SetShaderConstantData(usageIdx, slotIdx, constData, size);
}
///
@ -390,5 +390,6 @@ BF_EXPORT void BF_CALLTYPE DrawLayer_DrawToRenderTarget(DrawLayer* drawLayer, Te
renderDevice->PhysSetRenderState(renderDevice->mDefaultRenderState);
renderDevice->PhysSetRenderTarget(textureSegment->mTexture);
drawLayer->Draw();
drawLayer->Clear();
renderDevice->mCurRenderTarget = prevTarget;
}

View file

@ -99,8 +99,8 @@ public:
virtual DrawBatch* AllocateBatch(int minVtxCount, int minIdxCount);
void QueueRenderCmd(RenderCmd* renderCmd);
virtual RenderCmd* CreateSetTextureCmd(int textureIdx, Texture* texture) = 0;
virtual void SetShaderConstantData(int slotIdx, void* constData, int size) = 0;
virtual void SetShaderConstantDataTyped(int slotIdx, void* constData, int size, int* typeData, int typeCount);
virtual void SetShaderConstantData(int usageIdx, int slotIdx, void* constData, int size) = 0;
virtual void SetShaderConstantDataTyped(int usageIdx, int slotIdx, void* constData, int size, int* typeData, int typeCount);
public:
DrawLayer();

View file

@ -2,9 +2,24 @@
#include "BFApp.h"
#include "gfx/RenderDevice.h"
#include "gfx/ModelInstance.h"
#include "util/Dictionary.h"
#include "util/TLSingleton.h"
#include "FileStream.h"
#include "MemStream.h"
#pragma warning(disable:4190)
USING_NS_BF;
struct ModelManager
{
public:
Dictionary<String, ModelMaterialDef*> mMaterialMap;
};
ModelManager sModelManager;
static TLSingleton<String> gModelDef_TLStrReturn;
void Beefy::ModelAnimation::GetJointTranslation(int jointIdx, float frameNum, ModelJointTranslation* outJointTranslation)
{
// Frame 35
@ -40,6 +55,28 @@ BF_EXPORT ModelInstance* BF_CALLTYPE ModelDef_CreateModelInstance(ModelDef* mode
return gBFApp->mRenderDevice->CreateModelInstance(modelDef);
}
BF_EXPORT const char* BF_CALLTYPE ModelDef_GetInfo(ModelDef* modelDef)
{
String& outString = *gModelDef_TLStrReturn.Get();
for (int meshIdx = 0; meshIdx < (int)modelDef->mMeshes.mSize; meshIdx++)
{
auto mesh = modelDef->mMeshes[meshIdx];
for (int primIdx = 0; primIdx < (int)mesh.mPrimitives.mSize; primIdx++)
{
auto prims = mesh.mPrimitives[primIdx];
outString += StrFormat("%d\t%d\t%d\t%d", meshIdx, primIdx, prims.mIndices.size(), prims.mVertices.size());
for (auto& texPath : prims.mTexPaths)
{
outString += "\t";
outString += texPath;
}
outString += "\n";
}
}
return outString.c_str();
}
BF_EXPORT float BF_CALLTYPE ModelDef_GetFrameRate(ModelDef* modelDef)
{
return modelDef->mFrameRate;
@ -60,6 +97,14 @@ BF_EXPORT ModelAnimation* BF_CALLTYPE ModelDef_GetAnimation(ModelDef* modelDef,
return &modelDef->mAnims[animIdx];
}
BF_EXPORT void BF_CALLTYPE ModelDef_SetTextures(ModelDef* modelDef, int32 meshIdx, int32 primitivesIdx, char** paths, int32 pathCount)
{
auto& prims = modelDef->mMeshes[meshIdx].mPrimitives[primitivesIdx];
prims.mTexPaths.Clear();
for (int i = 0; i < pathCount; i++)
prims.mTexPaths.Add(paths[i]);
}
BF_EXPORT void BF_CALLTYPE ModelDefAnimation_GetJointTranslation(ModelAnimation* modelAnimation, int jointIdx, float frame, ModelJointTranslation* outJointTranslation)
{
modelAnimation->GetJointTranslation(jointIdx, frame, outJointTranslation);
@ -77,9 +122,169 @@ BF_EXPORT const char* BF_CALLTYPE ModelDefAnimation_GetName(ModelAnimation* mode
BF_EXPORT void BF_CALLTYPE ModelDefAnimation_Clip(ModelAnimation* modelAnimation, int startFrame, int numFrames)
{
modelAnimation->mFrames.erase(modelAnimation->mFrames.begin(), modelAnimation->mFrames.begin() + startFrame);
modelAnimation->mFrames.erase(modelAnimation->mFrames.begin() + numFrames, modelAnimation->mFrames.end());
modelAnimation->mFrames.RemoveRange(0, startFrame);
modelAnimation->mFrames.RemoveRange(numFrames, modelAnimation->mFrames.Count() - numFrames);
}
ModelDef::~ModelDef()
{
for (auto& materialInstance : mMaterials)
{
materialInstance.mDef->mRefCount--;
}
}
ModelMaterialDef* ModelMaterialDef::CreateOrGet(const StringImpl& prefix, const StringImpl& path)
{
StringT<128> key = prefix;
key += ":";
key += path;
ModelMaterialDef** modelMaterialDefPtr = NULL;
if (sModelManager.mMaterialMap.TryAdd(key, NULL, &modelMaterialDefPtr))
*modelMaterialDefPtr = new ModelMaterialDef();
return *modelMaterialDefPtr;
}
///
class ModelReader
{
public:
ModelDef* mModelDef;
DataStream* mFS;
public:
ModelReader(ModelDef* modelDef)
{
mFS = NULL;
mModelDef = modelDef;
}
~ModelReader()
{
delete mFS;
}
bool ReadFile()
{
int sig = mFS->ReadInt32();
if (sig != 0xBEEF0001)
return false;
int flags = mFS->ReadInt32();
Array<String> texNames;
int texNameSize = mFS->ReadInt32();
for (int i = 0; i < texNameSize; i++)
{
String path = mFS->ReadAscii32SizedString();
texNames.Add(path);
}
int idxCount = mFS->ReadInt32();
mModelDef->mMeshes.Add(ModelMesh());
auto& modelMesh = mModelDef->mMeshes[0];
modelMesh.mPrimitives.Add(ModelPrimitives());
auto& modelPrimitives = modelMesh.mPrimitives[0];
modelPrimitives.mFlags = (ModelPrimitives::Flags)flags;
modelPrimitives.mTexPaths = texNames;
modelPrimitives.mIndices.Resize(idxCount);
mFS->Read(modelPrimitives.mIndices.mVals, idxCount * 2);
int vtxCount = mFS->ReadInt32();
modelPrimitives.mVertices.Resize(vtxCount);
for (int i = 0; i < vtxCount; i++)
{
if ((flags & ModelPrimitives::Flags_Vertex_Position) != 0)
mFS->ReadT(modelPrimitives.mVertices[i].mPosition);
if ((flags & ModelPrimitives::Flags_Vertex_Tex0) != 0)
mFS->ReadT(modelPrimitives.mVertices[i].mTexCoords);
if ((flags & ModelPrimitives::Flags_Vertex_Tex1) != 0)
mFS->ReadT(modelPrimitives.mVertices[i].mBumpTexCoords);
}
return true;
}
bool ReadFile(const StringImpl& fileName, const StringImpl& baseDir)
{
if (fileName.Contains(':'))
{
int colon = (int)fileName.IndexOf(':');
String addrStr = fileName.Substring(1, colon - 1);
String lenStr = fileName.Substring(colon + 1);
void* addr = (void*)(intptr)strtoll(addrStr.c_str(), NULL, 16);
int len = (int)strtol(lenStr.c_str(), NULL, 10);
MemStream* memStream = new MemStream(addr, len, false);
mFS = memStream;
}
else
{
FileStream* fs = new FileStream();
mFS = fs;
if (!fs->Open(fileName, "rb"))
return false;
}
return ReadFile();
}
};
BF_EXPORT void* BF_CALLTYPE Res_OpenModel(const char* fileName, const char* baseDir, void* vertexDefinition)
{
ModelDef* modelDef = new ModelDef();
modelDef->mLoadDir = baseDir;
ModelReader reader(modelDef);
if (!reader.ReadFile(fileName, baseDir))
{
delete modelDef;
return NULL;
}
return modelDef;
}
BF_EXPORT StringView BF_CALLTYPE Res_SerializeModel(ModelDef* modelDef)
{
DynMemStream ms;
ms.Write((int)0xBEEF0001);
for (auto& mesh : modelDef->mMeshes)
{
for (auto& prims : mesh.mPrimitives)
{
ms.Write((int)prims.mFlags);
ms.Write(prims.mTexPaths.mSize);
for (auto& path : prims.mTexPaths)
ms.Write(path);
ms.Write((int)prims.mIndices.mSize);
ms.Write(prims.mIndices.mVals, prims.mIndices.mSize * 2);
ms.Write((int)prims.mVertices.mSize);
for (int i = 0; i < prims.mVertices.mSize; i++)
{
auto& vtx = prims.mVertices[i];
if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Position) != 0)
ms.WriteT(vtx.mPosition);
if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Tex0) != 0)
ms.WriteT(vtx.mTexCoords);
if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Tex1) != 0)
ms.WriteT(vtx.mBumpTexCoords);
if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Color) != 0)
ms.WriteT(vtx.mColor);
if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Normal) != 0)
ms.WriteT(vtx.mNormal);
if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Tangent) != 0)
ms.WriteT(vtx.mTangent);
}
}
}
String& outString = *gModelDef_TLStrReturn.Get();
return outString;
}

View file

@ -3,6 +3,8 @@
#include "Common.h"
#include "util/Quaternion.h"
#include "util/Vector.h"
#include "util/Array.h"
#include "gfx/Texture.h"
#include <vector>
NS_BF_BEGIN;
@ -18,14 +20,14 @@ public:
class ModelAnimationFrame
{
public:
std::vector<ModelJointTranslation> mJointTranslations;
Array<ModelJointTranslation> mJointTranslations;
};
class ModelAnimation
{
public:
String mName;
std::vector<ModelAnimationFrame> mFrames;
Array<ModelAnimationFrame> mFrames;
public:
void GetJointTranslation(int jointIdx, float frameNum, ModelJointTranslation* outJointTranslation);
@ -55,14 +57,113 @@ public:
Matrix4 mPoseInvMatrix;
};
class ModelMetalicRoughness
{
public:
Vector3 mBaseColorFactor;
float mMetallicFactor;
float mRoughnessFactor;
public:
ModelMetalicRoughness()
{
mMetallicFactor = 0;
mRoughnessFactor = 0;
}
};
class ModelMaterialDef
{
public:
class TextureParameterValue
{
public:
String mName;
String mTexturePath;
public:
TextureParameterValue()
{
}
~TextureParameterValue()
{
}
};
public:
String mName;
int mRefCount;
bool mInitialized;
OwnedArray<TextureParameterValue> mTextureParameterValues;
public:
ModelMaterialDef()
{
mRefCount = 0;
mInitialized = false;
}
static ModelMaterialDef* CreateOrGet(const StringImpl& prefix, const StringImpl& path);
};
class ModelMaterialInstance
{
public:
ModelMaterialDef* mDef;
String mName;
ModelMetalicRoughness mModelMetalicRoughness;
};
class ModelPrimitives
{
public:
enum Flags
{
Flags_None = 0,
Flags_Vertex_Position = 1,
Flags_Vertex_Tex0 = 2,
Flags_Vertex_Tex1 = 4,
Flags_Vertex_Tex2 = 8,
Flags_Vertex_Color = 0x10,
Flags_Vertex_Normal = 0x20,
Flags_Vertex_Tangent = 0x40,
};
public:
Array<ModelVertex> mVertices;
Array<uint16> mIndices;
ModelMaterialInstance* mMaterial;
Array<String> mTexPaths;
Flags mFlags;
public:
ModelPrimitives()
{
mMaterial = NULL;
mFlags = Flags_None;
}
};
class ModelMesh
{
public:
String mName;
//String mTexFileName;
//String mBumpFileName;
Array<ModelPrimitives> mPrimitives;
};
class ModelNode
{
public:
String mName;
std::vector<ModelVertex> mVertices;
std::vector<uint16> mIndices;
String mTexFileName;
String mBumpFileName;
Vector3 mTranslation;
Vector4 mRotation;
ModelMesh* mMesh;
Array<ModelNode*> mChildren;
};
class ModelDef
@ -70,9 +171,14 @@ class ModelDef
public:
String mLoadDir;
float mFrameRate;
std::vector<ModelMesh> mMeshes;
std::vector<ModelJoint> mJoints;
std::vector<ModelAnimation> mAnims;
Array<ModelMesh> mMeshes;
Array<ModelJoint> mJoints;
Array<ModelAnimation> mAnims;
Array<ModelNode> mNodes;
Array<ModelMaterialInstance> mMaterials;
public:
~ModelDef();
};
NS_BF_END;

View file

@ -6,8 +6,8 @@ ModelInstance::ModelInstance(ModelDef* modelDef)
{
mNext = NULL;
mModelDef = modelDef;
mJointTranslations.resize(mModelDef->mJoints.size());
mMeshesVisible.insert(mMeshesVisible.begin(), mModelDef->mMeshes.size(), true);
mJointTranslations.Resize(mModelDef->mJoints.size());
mMeshesVisible.Insert(0, mModelDef->mMeshes.size(), true);
}
void Beefy::ModelInstance::SetJointPosition(int jointIdx, const ModelJointTranslation& jointTranslation)

View file

@ -11,8 +11,8 @@ class ModelInstance : public RenderCmd
{
public:
ModelDef* mModelDef;
std::vector<ModelJointTranslation> mJointTranslations;
std::vector<bool> mMeshesVisible;
Array<ModelJointTranslation> mJointTranslations;
Array<bool> mMeshesVisible;
public:
ModelInstance(ModelDef* modelDef);

View file

@ -21,6 +21,7 @@ RenderState::RenderState()
mDepthFunc = DepthFunc_Always;
mShader = NULL;
mClipped = false;
mTexWrap = false;
}
RenderTarget::RenderTarget()
@ -103,8 +104,8 @@ Texture* RenderDevice::LoadTexture(const StringImpl& fileName, int flags)
int dotPos = (int)fileName.LastIndexOf('.');
String ext;
if (dotPos != -1)
ext = fileName.Substring(dotPos);
ext = fileName.Substring(dotPos);
ImageData* imageData = NULL;
bool handled = false;
bool failed = false;

View file

@ -182,6 +182,7 @@ public:
bool mWriteDepthBuffer;
DepthFunc mDepthFunc;
bool mClipped;
bool mTexWrap;
Rect mClipRect;
CullMode mCullMode;
@ -190,6 +191,7 @@ public:
virtual ~RenderState() {}
virtual void SetShader(Shader* shader) { mShader = shader; }
virtual void SetTexWrap(bool wrap) { mTexWrap = wrap; }
virtual void SetClipped(bool clipped) { mClipped = clipped; }
virtual void SetClipRect(const Rect& rect) { mClipRect = rect; }
virtual void SetWriteDepthBuffer(bool writeDepthBuffer) { mWriteDepthBuffer = writeDepthBuffer; }

875
BeefySysLib/gfx/glTF.cpp Normal file
View file

@ -0,0 +1,875 @@
#include "glTF.h"
#include "gfx/ModelInstance.h"
#include "util/Json.h"
#include "gfx/RenderDevice.h"
#include "BFApp.h"
USING_NS_BF;
static bool IsWhitespace(char c)
{
return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
}
class GLTFPropsParser
{
public:
enum NodeKind
{
NodeKind_None,
NodeKind_End,
NodeKind_LBrace,
NodeKind_RBrace,
NodeKind_LBracket,
NodeKind_RBracket,
NodeKind_Equals,
NodeKind_Index,
NodeKind_Integer,
NodeKind_Float,
NodeKind_String
};
struct Node
{
public:
NodeKind mKind;
int mStart;
int mEnd;
union
{
int mValueInt;
float mValueFloat;
};
public:
Node()
{
mKind = NodeKind_None;
mStart = -1;
mEnd = -1;
mValueInt = 0;
}
};
public:
char* mStart;
char* mPtr;
char* mEnd;
Node mNext;
public:
GLTFPropsParser(const StringImpl& str)
{
mStart = str.mPtr;
mPtr = mStart;
mEnd = mStart + str.mLength;
}
// double ParseLiteralDouble()
// {
// char buf[256];
// int len = BF_MAX(mTokenEnd - mTokenStart, 255);
//
// memcpy(buf, &mSrc[mTokenStart], len);
// char c = buf[len - 1];
// if ((c == 'd') || (c == 'D') || (c == 'f') || (c == 'F'))
// buf[len - 1] = '\0';
// else
// buf[len] = '\0';
//
// return strtod(buf, NULL);
// }
Node PeekNext()
{
if (mNext.mKind != NodeKind_None)
return mNext;
while (true)
{
if (mPtr >= mEnd)
{
mNext.mKind = NodeKind_End;
return mNext;
}
char* start = mPtr;
char c = *(mPtr++);
if (c == '{')
mNext.mKind = NodeKind_LBrace;
else if (c == '}')
mNext.mKind = NodeKind_RBrace;
else if (c == '[')
mNext.mKind = NodeKind_LBracket;
else if (c == ']')
mNext.mKind = NodeKind_RBracket;
else if (c == '=')
mNext.mKind = NodeKind_Equals;
if (mNext.mKind != NodeKind_None)
{
mNext.mStart = (int)(mPtr - mStart - 1);
mNext.mEnd = (int)(mPtr - mStart);
return mNext;
}
if ((c >= '0') && (c <= '9'))
{
bool hadDot = false;
while (mPtr < mEnd)
{
char c = *mPtr;
if (c == '.')
{
mPtr++;
hadDot = true;
}
else if ((c >= '0') && (c <= '9'))
{
mPtr++;
}
else
break;
}
mNext.mStart = (int)(start - mStart);
mNext.mEnd = (int)(mPtr - mStart);
char buf[256];
int len = BF_MIN((int)(mPtr - start), 255);
memcpy(buf, start, len);
char c = buf[len - 1];
if ((c == 'd') || (c == 'D') || (c == 'f') || (c == 'F'))
buf[len - 1] = '\0';
else
buf[len] = '\0';
if (hadDot)
{
mNext.mKind = NodeKind_Float;
mNext.mValueFloat = (float)strtod(buf, NULL);
}
else
{
mNext.mKind = NodeKind_Integer;
mNext.mValueInt = atoi(buf);
}
return mNext;
}
if (!IsWhitespace(c))
{
char* lastCPtr = start;
while (mPtr < mEnd)
{
char c = *mPtr;
if ((c == '}') || (c == '=') || (c == '[') || (c == '\r') || (c == '\n'))
break;
if (c != ' ')
lastCPtr = mPtr;
mPtr++;
}
mPtr = lastCPtr + 1;
mNext.mStart = (int)(start - mStart);
mNext.mEnd = (int)(mPtr - mStart);
mNext.mKind = NodeKind_String;
return mNext;
}
}
}
Node GetNext()
{
auto node = PeekNext();
mNext = Node();
return node;
}
StringView GetStringView(const Node& node)
{
return StringView(mStart + node.mStart, node.mEnd - node.mStart);
}
StringView GetStringView(const Node& node, StringView& prefix)
{
auto stringView = StringView(mStart + node.mStart, node.mEnd - node.mStart);
if (!stringView.EndsWith('\''))
{
prefix = "";
return stringView;
}
int strStartIdx = (int)stringView.IndexOf('\'');
prefix = StringView(stringView, 0, strStartIdx);
return StringView(stringView, strStartIdx + 1, (int)stringView.mLength - strStartIdx - 2);
}
bool GetNextStringView(StringView& prefix, StringView& value)
{
auto node = GetNext();
if (node.mKind != NodeKind_String)
return false;
auto stringView = StringView(mStart + node.mStart, node.mEnd - node.mStart);
if (!stringView.EndsWith('\''))
{
prefix = "";
value = stringView;
return true;
}
int strStartIdx = (int)stringView.IndexOf('\'');
prefix = StringView(stringView, 0, strStartIdx);
value = StringView(stringView, strStartIdx + 1, (int)stringView.mLength - strStartIdx - 2);
return true;
}
};
enum ComponentType
{
Int8 = 5120,
UInt8 = 5121,
Int16 = 5122,
UInt16 = 5123,
UInt32 = 5125,
Float = 5126,
};
BF_EXPORT void* BF_CALLTYPE Res_OpenGLTF(const char* fileName, const char* baseDir, void* vertexDefinition)
{
ModelDef* modelDef = new ModelDef();
GLTFReader reader(modelDef);
if (!reader.ReadFile(fileName, baseDir))
{
delete modelDef;
return NULL;
}
return modelDef;
}
GLTFReader::GLTFReader(ModelDef* modelDef)
{
mModelDef = modelDef;
}
GLTFReader::~GLTFReader()
{
}
struct DataSpan
{
uint8* mPtr;
int mSize;
};
struct DataAccessor
{
uint8* mPtr;
int mSize;
int mCount;
ComponentType mComponentType;
};
template <typename T>
static void ReadBuffer(DataAccessor& dataAccessor, T* outPtr, int outStride)
{
for (int i = 0; i < dataAccessor.mCount; i++)
*(T*)((uint8*)outPtr + i * outStride) = ((T*)dataAccessor.mPtr)[i];
}
template <typename T>
static void ReadBuffer(DataAccessor& dataAccessor, T* outPtr, int outStride, int inStride)
{
for (int i = 0; i < dataAccessor.mCount; i++)
*(T*)((uint8*)outPtr + i * outStride) = *(T*)(dataAccessor.mPtr + i * inStride);
}
static void TrySkipValue(GLTFPropsParser& propsParser)
{
auto nextNode = propsParser.PeekNext();
if (nextNode.mKind == GLTFPropsParser::NodeKind_LBracket)
{
propsParser.GetNext();
propsParser.GetNext();
propsParser.GetNext();
nextNode = propsParser.PeekNext();
}
if (nextNode.mKind == GLTFPropsParser::NodeKind_Equals)
{
propsParser.GetNext();
int depth = 0;
do
{
auto node = propsParser.GetNext();
if (node.mKind == GLTFPropsParser::NodeKind_End)
return;
if (node.mKind == GLTFPropsParser::NodeKind_LBrace)
depth++;
else if (node.mKind == GLTFPropsParser::NodeKind_RBrace)
depth--;
if (node.mKind == GLTFPropsParser::NodeKind_LBracket)
depth++;
if (node.mKind == GLTFPropsParser::NodeKind_LBracket)
depth--;
} while (depth > 0);
}
}
static bool ExpectIndex(GLTFPropsParser& propsParser, int& idx)
{
auto node = propsParser.GetNext();
if (node.mKind != GLTFPropsParser::NodeKind_LBracket)
return false;
node = propsParser.GetNext();
if (node.mKind != GLTFPropsParser::NodeKind_Integer)
return false;
idx = node.mValueInt;
node = propsParser.GetNext();
if (node.mKind != GLTFPropsParser::NodeKind_RBracket)
return false;
return true;
};
static bool ExpectOpen(GLTFPropsParser& propsParser)
{
if (propsParser.GetNext().mKind != GLTFPropsParser::NodeKind_LBrace)
return false;
return true;
};
static bool ExpectClose(GLTFPropsParser& propsParser)
{
if (propsParser.GetNext().mKind != GLTFPropsParser::NodeKind_RBrace)
return false;
return true;
};
static bool ExpectEquals(GLTFPropsParser& propsParser)
{
if (propsParser.GetNext().mKind != GLTFPropsParser::NodeKind_Equals)
return false;
return true;
};
bool GLTFReader::ParseMaterialDef(ModelMaterialDef* materialDef, const StringImpl& matText)
{
GLTFPropsParser propsParser(matText);
while (true)
{
auto node = propsParser.GetNext();
if (node.mKind == GLTFPropsParser::NodeKind_End)
break;
if (node.mKind == GLTFPropsParser::NodeKind_String)
{
auto key = propsParser.GetStringView(node);
if (key == "Parent")
{
if (propsParser.GetNext().mKind != GLTFPropsParser::NodeKind_Equals)
return false;
auto valueNode = propsParser.GetNext();
if (valueNode.mKind != GLTFPropsParser::NodeKind_String)
return false;
StringView prefix;
StringView str = propsParser.GetStringView(valueNode, prefix);
auto parentMaterialDef = LoadMaterial(str);
}
else if (key == "TextureParameterValues")
{
int count = 0;
if (!ExpectIndex(propsParser, count))
return false;
if (!ExpectEquals(propsParser))
return false;
if (!ExpectOpen(propsParser))
return false;
while (true)
{
node = propsParser.GetNext();
if (node.mKind == GLTFPropsParser::NodeKind_RBrace)
break;
if (node.mKind != GLTFPropsParser::NodeKind_String)
return false;
StringView prefix;
StringView str = propsParser.GetStringView(node, prefix);
if (str == "TextureParameterValues")
{
auto textureParamValue = materialDef->mTextureParameterValues.Alloc();
int idx = 0;
if (!ExpectIndex(propsParser, idx))
return false;
if (!ExpectEquals(propsParser))
return false;
if (!ExpectOpen(propsParser))
return false;
while (true)
{
node = propsParser.GetNext();
if (node.mKind == GLTFPropsParser::NodeKind_RBrace)
break;
if (node.mKind != GLTFPropsParser::NodeKind_String)
return false;
str = propsParser.GetStringView(node, prefix);
if (str == "ParameterInfo")
{
if (!ExpectEquals(propsParser))
return false;
if (!ExpectOpen(propsParser))
return false;
if (!propsParser.GetNextStringView(prefix, str))
return false;
if (!ExpectEquals(propsParser))
return false;
if (!propsParser.GetNextStringView(prefix, str))
return false;
textureParamValue->mName = str;
if (!ExpectClose(propsParser))
return false;
}
else if (str == "ParameterValue")
{
if (!ExpectEquals(propsParser))
return false;
if (!propsParser.GetNextStringView(prefix, str))
return false;
String path = mRootDir;
path += str;
int dotPos = (int)path.IndexOf('.');
if (dotPos != -1)
path.RemoveToEnd(dotPos);
path += ".tga";
textureParamValue->mTexturePath = path;
// Texture* texture = gBFApp->mRenderDevice->LoadTexture(path, 0);
// textureParamValue->mTexture = texture;
}
else
TrySkipValue(propsParser);
}
}
else
{
TrySkipValue(propsParser);
}
}
}
else
{
TrySkipValue(propsParser);
}
}
}
return true;
}
ModelMaterialDef* GLTFReader::LoadMaterial(const StringImpl& relPath)
{
String propsPath;
if (relPath.StartsWith('/'))
{
propsPath = mRootDir + relPath;
int dotPos = (int)propsPath.LastIndexOf('.');
if (dotPos > 0)
propsPath.RemoveToEnd(dotPos);
propsPath += ".props.txt";
}
else if (mBasePathName.Contains("staticmesh"))
propsPath = GetFileDir(mBasePathName) + "/" + relPath + ".props.txt";
else
propsPath = GetFileDir(mBasePathName) + "/materials/" + relPath + ".props.txt";
ModelMaterialDef* materialDef = ModelMaterialDef::CreateOrGet("GLTF", propsPath);
if (materialDef->mInitialized)
return materialDef;
materialDef->mInitialized = true;
String propText;
if (LoadTextData(propsPath, propText))
{
if (!ParseMaterialDef(materialDef, propText))
{
// Had error
}
}
return materialDef;
}
bool GLTFReader::LoadModelProps(const StringImpl& propsPath)
{
String propText;
if (!LoadTextData(propsPath, propText))
return false;
GLTFPropsParser propsParser(propText);
while (true)
{
auto node = propsParser.GetNext();
if (node.mKind == GLTFPropsParser::NodeKind_End)
break;
if (node.mKind == GLTFPropsParser::NodeKind_String)
{
auto key = propsParser.GetStringView(node);
if (key == "StaticMaterials")
{
int count = 0;
if (!ExpectIndex(propsParser, count))
return false;
if (!ExpectEquals(propsParser))
return false;
if (!ExpectOpen(propsParser))
return false;
while (true)
{
node = propsParser.GetNext();
if (node.mKind == GLTFPropsParser::NodeKind_RBrace)
break;
if (node.mKind != GLTFPropsParser::NodeKind_String)
return false;
StringView prefix;
StringView str = propsParser.GetStringView(node, prefix);
if (str == "StaticMaterials")
{
StaticMaterial staticMaterial;
int idx = 0;
if (!ExpectIndex(propsParser, idx))
return false;
if (!ExpectEquals(propsParser))
return false;
if (!ExpectOpen(propsParser))
return false;
while (true)
{
node = propsParser.GetNext();
if (node.mKind == GLTFPropsParser::NodeKind_RBrace)
break;
if (node.mKind != GLTFPropsParser::NodeKind_String)
return false;
str = propsParser.GetStringView(node, prefix);
if (str == "MaterialSlotName")
{
if (!ExpectEquals(propsParser))
return false;
if (!propsParser.GetNextStringView(prefix, str))
return false;
staticMaterial.mMaterialSlotName = str;
}
else if (str == "MaterialInterface")
{
if (!ExpectEquals(propsParser))
return false;
if (!propsParser.GetNextStringView(prefix, str))
return false;
staticMaterial.mMaterialDef = LoadMaterial(str);
}
else
TrySkipValue(propsParser);
}
mStaticMaterials.Add(staticMaterial);
}
else
{
TrySkipValue(propsParser);
}
}
}
else
{
TrySkipValue(propsParser);
}
}
}
return true;
}
bool GLTFReader::ReadFile(const StringImpl& filePath, const StringImpl& rootDir)
{
String basePathName;
int dotPos = (int)filePath.LastIndexOf('.');
if (dotPos > 0)
basePathName = filePath.Substring(0, dotPos);
else
basePathName = basePathName;
mBasePathName = basePathName;
mRootDir = rootDir;
String jsonPath = basePathName + ".gltf";
char* textData = LoadTextData(jsonPath, NULL);
if (textData == NULL)
return false;
defer({ delete textData; });
Json* jRoot = Json::Parse(textData);
if (jRoot == NULL)
return false;
defer({ delete jRoot; });
LoadModelProps(basePathName + ".props.txt");
Array<Array<uint8>> buffers;
Array<DataSpan> bufferViews;
Array<DataAccessor> dataAccessors;
if (auto jBuffers = jRoot->GetObjectItem("buffers"))
{
for (auto jBuffer = jBuffers->mChild; jBuffer != NULL; jBuffer = jBuffer->mNext)
{
Array<uint8> data;
if (auto jName = jBuffer->GetObjectItem("uri"))
{
if (jName->mValueString != NULL)
{
String dataPath = GetFileDir(basePathName) + "/" + jName->mValueString;
int size = 0;
uint8* rawData = LoadBinaryData(dataPath, &size);
if (rawData != NULL)
data.Insert(0, rawData, size);
}
}
buffers.Add(data);
}
}
if (auto jBufferViews = jRoot->GetObjectItem("bufferViews"))
{
for (auto jBufferView = jBufferViews->mChild; jBufferView != NULL; jBufferView = jBufferView->mNext)
{
int bufferIdx = 0;
int byteOffset = 0;
int byteLength = 0;
if (auto jBufferIdx = jBufferView->GetObjectItem("buffer"))
bufferIdx = jBufferIdx->mValueInt;
if (auto jByteOffset = jBufferView->GetObjectItem("byteOffset"))
byteOffset = jByteOffset->mValueInt;
if (auto jByteLength = jBufferView->GetObjectItem("byteLength"))
byteLength = jByteLength->mValueInt;
bufferViews.Add(DataSpan{ buffers[bufferIdx].mVals + byteOffset, byteLength });
}
}
if (auto jAccessors = jRoot->GetObjectItem("accessors"))
{
for (auto jAccessor = jAccessors->mChild; jAccessor != NULL; jAccessor = jAccessor->mNext)
{
DataAccessor dataAccessor = { 0 };
if (auto jBufferIdx = jAccessor->GetObjectItem("bufferView"))
{
DataSpan& dataSpan = bufferViews[jBufferIdx->mValueInt];
dataAccessor.mPtr = dataSpan.mPtr;
dataAccessor.mSize = dataSpan.mSize;
}
if (auto jCount = jAccessor->GetObjectItem("count"))
dataAccessor.mCount = jCount->mValueInt;
if (auto jCount = jAccessor->GetObjectItem("componentType"))
dataAccessor.mComponentType = (ComponentType)jCount->mValueInt;
dataAccessors.Add(dataAccessor);
}
}
auto _GetFloat3 = [&](Json* json, Vector3& vec)
{
int i = 0;
for (auto jItem = json->mChild; jItem != NULL; jItem = jItem->mNext)
{
if (i == 0)
vec.mX = (float)jItem->mValueDouble;
if (i == 1)
vec.mY = (float)jItem->mValueDouble;
if (i == 2)
vec.mZ = (float)jItem->mValueDouble;
i++;
}
};
auto _GetFloat4 = [&](Json* json, Vector4& vec)
{
int i = 0;
for (auto jItem = json->mChild; jItem != NULL; jItem = jItem->mNext)
{
if (i == 0)
vec.mX = (float)jItem->mValueDouble;
if (i == 1)
vec.mY = (float)jItem->mValueDouble;
if (i == 2)
vec.mZ = (float)jItem->mValueDouble;
if (i == 3)
vec.mW = (float)jItem->mValueDouble;
i++;
}
};
if (auto jMaterials = jRoot->GetObjectItem("materials"))
{
int materialIdx = 0;
for (auto jMaterial = jMaterials->mChild; jMaterial != NULL; jMaterial = jMaterial->mNext)
{
ModelMaterialInstance modelMaterialInstance;
if (auto jName = jMaterial->GetObjectItem("name"))
{
if (jName->mValueString != NULL)
{
modelMaterialInstance.mName = jName->mValueString;
String matPath = jName->mValueString;
if (materialIdx < mStaticMaterials.mSize)
matPath = mStaticMaterials[materialIdx].mMaterialSlotName;
ModelMaterialDef* materialDef = LoadMaterial(matPath);
modelMaterialInstance.mDef = materialDef;
}
}
if (auto jPBRMetallicRoughness = jMaterial->GetObjectItem("pbrMetallicRoughness"))
{
}
mModelDef->mMaterials.Add(modelMaterialInstance);
materialIdx++;
}
}
if (auto jMeshes = jRoot->GetObjectItem("meshes"))
{
for (auto jMesh = jMeshes->mChild; jMesh != NULL; jMesh = jMesh->mNext)
{
ModelMesh modelMesh;
if (auto jName = jMesh->GetObjectItem("name"))
{
if (jName->mValueString != NULL)
modelMesh.mName = jName->mValueString;
}
if (auto jPrimitives = jMesh->GetObjectItem("primitives"))
{
modelMesh.mPrimitives.Resize(jPrimitives->GetArraySize());
int primCount = 0;
for (auto jPrimitive = jPrimitives->mChild; jPrimitive != NULL; jPrimitive = jPrimitive->mNext)
{
ModelPrimitives& modelPrimitives = modelMesh.mPrimitives[primCount];
if (auto jIndices = jPrimitive->GetObjectItem("indices"))
{
auto& dataAccessor = dataAccessors[jIndices->mValueInt];
modelPrimitives.mIndices.ResizeRaw(dataAccessor.mCount);
for (int i = 0; i < dataAccessor.mCount; i++)
modelPrimitives.mIndices[i] = *(uint16*)(dataAccessor.mPtr + i * 2);
}
if (auto jIndices = jPrimitive->GetObjectItem("material"))
modelPrimitives.mMaterial = &mModelDef->mMaterials[jIndices->mValueInt];
if (auto jAttributes = jPrimitive->GetObjectItem("attributes"))
{
if (auto jPosition = jAttributes->GetObjectItem("POSITION"))
{
auto& dataAccessor = dataAccessors[jPosition->mValueInt];
modelPrimitives.mVertices.Resize(dataAccessor.mCount);
ReadBuffer<Vector3>(dataAccessor, &modelPrimitives.mVertices[0].mPosition, sizeof(ModelVertex));
}
if (auto jNormal = jAttributes->GetObjectItem("NORMAL"))
ReadBuffer<Vector3>(dataAccessors[jNormal->mValueInt], &modelPrimitives.mVertices[0].mNormal, sizeof(ModelVertex));
if (auto jTangent = jAttributes->GetObjectItem("TANGENT"))
ReadBuffer<Vector3>(dataAccessors[jTangent->mValueInt], &modelPrimitives.mVertices[0].mTangent, sizeof(ModelVertex), sizeof(Vector4));
if (auto jColor = jAttributes->GetObjectItem("COLOR_0"))
ReadBuffer<uint32>(dataAccessors[jColor->mValueInt], &modelPrimitives.mVertices[0].mColor, sizeof(ModelVertex));
if (auto jTexCoords = jAttributes->GetObjectItem("TEXCOORD_0"))
{
ReadBuffer<TexCoords>(dataAccessors[jTexCoords->mValueInt], &modelPrimitives.mVertices[0].mTexCoords, sizeof(ModelVertex));
for (auto& vertex : modelPrimitives.mVertices)
{
vertex.mTexCoords.mV = 1.0f - vertex.mTexCoords.mV;
}
}
if (auto jTexCoords = jAttributes->GetObjectItem("TEXCOORD_1"))
{
ReadBuffer<TexCoords>(dataAccessors[jTexCoords->mValueInt], &modelPrimitives.mVertices[0].mTexCoords, sizeof(ModelVertex));
for (auto& vertex : modelPrimitives.mVertices)
{
//vertex.mTexCoords.mU = 1.0f - vertex.mTexCoords.mU;
vertex.mTexCoords.mV = 1.0f - vertex.mTexCoords.mV;
}
}
else
{
for (auto& vertex : modelPrimitives.mVertices)
vertex.mBumpTexCoords = vertex.mTexCoords;
}
}
primCount++;
}
}
mModelDef->mMeshes.Add(modelMesh);
}
}
if (auto jNodes = jRoot->GetObjectItem("nodes"))
{
mModelDef->mNodes.Reserve(jNodes->GetArraySize());
for (auto jNode = jNodes->mChild; jNode != NULL; jNode = jNode->mNext)
{
ModelNode modelNode;
if (auto jName = jNode->GetObjectItem("name"))
{
if (jName->mValueString != NULL)
modelNode.mName = jName->mValueString;
}
if (auto jChildren = jNode->GetObjectItem("children"))
{
for (auto jChild = jChildren->mChild; jChild != NULL; jChild = jChild->mNext)
{
int childIdx = jChild->mValueInt;
modelNode.mChildren.Add(mModelDef->mNodes.mVals + childIdx);
}
}
if (auto jTranslation = jNode->GetObjectItem("translation"))
_GetFloat3(jTranslation, modelNode.mTranslation);
if (auto jTranslation = jNode->GetObjectItem("rotation"))
_GetFloat4(jTranslation, modelNode.mRotation);
if (auto jMesh = jNode->GetObjectItem("mesh"))
modelNode.mMesh = mModelDef->mMeshes.mVals + jMesh->mValueInt;
mModelDef->mNodes.Add(modelNode);
}
}
return true;
}

43
BeefySysLib/gfx/glTF.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
#pragma once
#include "Common.h"
#include "util/Quaternion.h"
#include "util/Vector.h"
#include "util/Array.h"
#include "FileStream.h"
#include <vector>
NS_BF_BEGIN;
class ModelDef;
class ModelMaterialDef;
class GLTFReader
{
public:
class StaticMaterial
{
public:
ModelMaterialDef* mMaterialDef;
String mMaterialSlotName;
};
public:
String mBasePathName;
String mRootDir;
ModelDef* mModelDef;
Array<StaticMaterial> mStaticMaterials;
public:
GLTFReader(ModelDef* modelDef);
~GLTFReader();
bool ParseMaterialDef(ModelMaterialDef* materialDef, const StringImpl& matText);
ModelMaterialDef* LoadMaterial(const StringImpl& path);
bool LoadModelProps(const StringImpl& relPath);
bool ReadFile(const StringImpl& filePath, const StringImpl& rootDir);
};
NS_BF_END;