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:
parent
70680fdf39
commit
f26df6c86b
32 changed files with 2370 additions and 165 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
875
BeefySysLib/gfx/glTF.cpp
Normal 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
43
BeefySysLib/gfx/glTF.h
Normal 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;
|
Loading…
Add table
Add a link
Reference in a new issue