1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +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

@ -727,7 +727,7 @@ namespace Beefy
0.10f, 0.00f, 1.05f, 0,
0, 0, 0, 1);*/
mGraphics.SetShaderConstantData(0, &mColorMatrix.ValueRef, mColorMatrixDataDef);
mGraphics.SetVertexShaderConstantData(0, &mColorMatrix.ValueRef, mColorMatrixDataDef);
}
window.Draw(mGraphics);
window.PostDraw(mGraphics);

View file

@ -79,6 +79,10 @@ namespace Beefy.gfx
const int32 CLIP_STACK_SIZE = 256;
public Rect?[] mClipStack = new Rect?[CLIP_STACK_SIZE] ~ delete _;
public bool mTexWrap;
protected DisposeProxy mTexWrapDisableProxy ~ delete _;
protected DisposeProxy mTexWrapEnableProxy ~ delete _;
public int32 mClipStackIdx = 0;
public Rect? mClipRect = null;
@ -106,6 +110,10 @@ namespace Beefy.gfx
mClipDisposeProxy = new DisposeProxy();
mClipDisposeProxy.mDisposeProxyDelegate = new => PopClip;
mRenderStateDisposeProxy = new DisposeProxy();
mTexWrapDisableProxy = new DisposeProxy();
mTexWrapDisableProxy.mDisposeProxyDelegate = new () => { PopTexWrap(false); };
mTexWrapEnableProxy = new DisposeProxy();
mTexWrapEnableProxy.mDisposeProxyDelegate = new () => { PopTexWrap(true); };
mWhiteDot = Image.LoadFromFile("!white");
@ -341,7 +349,7 @@ namespace Beefy.gfx
Rect rectThing = mClipRect.Value;
mClipRect = rectThing;
var clipRenderState = AllocRenderState(mDefaultShader, mClipRect);
var clipRenderState = AllocRenderState(mDefaultShader, mClipRect, mTexWrap);
//clipRenderState.ClipRect = mClipRect;
PushRenderState(clipRenderState);
@ -349,7 +357,7 @@ namespace Beefy.gfx
return mClipDisposeProxy;
}
RenderState AllocRenderState(Shader shader, Rect? clipRect)
RenderState AllocRenderState(Shader shader, Rect? clipRect, bool texWrap)
{
RenderState renderState = null;
var curRenderState = mRenderStateStack[mRenderStateStackIdx];
@ -365,6 +373,7 @@ namespace Beefy.gfx
}
else
renderState = RenderState.Create(curRenderState);
renderState.TexWrap = texWrap;
renderState.Shader = shader;
renderState.ClipRect = clipRect;
return renderState;
@ -375,16 +384,33 @@ namespace Beefy.gfx
mClipStackIdx++;
mClipStack[mClipStackIdx] = null;
mClipRect = null;
var clipRenderState = AllocRenderState(mDefaultShader, null);
var clipRenderState = AllocRenderState(mDefaultShader, mClipRect, mTexWrap);
//clipRenderState.ClipRect = null;
PushRenderState(clipRenderState);
return mClipDisposeProxy;
}
public DisposeProxy PushTexWrap(bool texWrap)
{
bool prevTexWrap = mTexWrap;
mTexWrap = texWrap;
var clipRenderState = AllocRenderState(mDefaultShader, mClipRect, mTexWrap);
PushRenderState(clipRenderState);
return prevTexWrap ? mTexWrapEnableProxy : mTexWrapDisableProxy;
}
protected void PopTexWrap(bool texWrap)
{
mTexWrap = texWrap;
PopRenderState();
}
public void PushTextRenderState()
{
var textRenderState = AllocRenderState(mTextShader, mClipRect);
var textRenderState = AllocRenderState(mTextShader, mClipRect, mTexWrap);
//textRenderState.ClipRect = mClipRect;
//textRenderState.Shader = mTextShader;
PushRenderState(textRenderState);
@ -419,10 +445,10 @@ namespace Beefy.gfx
static extern void Gfx_DrawIndexedVertices2D(int32 vertexSize, void* vtxData, int32 vtxCount, uint16* idxData, int32 idxCount, float a, float b, float c, float d, float tx, float ty, float z);
[CallingConvention(.Stdcall), CLink]
static extern void Gfx_SetShaderConstantData(int32 slotIdx, void* data, int32 size);
static extern void Gfx_SetShaderConstantData(int32 usageIdx, int32 slotIdx, void* data, int32 size);
[CallingConvention(.Stdcall), CLink]
static extern void Gfx_SetShaderConstantDataTyped(int32 slotIdx, void* data, int32 size, int32* typeData, int32 typeCount);
static extern void Gfx_SetShaderConstantDataTyped(int usageIdx, int32 slotIdx, void* data, int32 size, int32* typeData, int32 typeCount);
[CallingConvention(.Stdcall), CLink]
static extern void Gfx_DrawQuads(void* textureSegment, Vertex3D* vertices, int32 vtxCount);
@ -778,21 +804,32 @@ namespace Beefy.gfx
mMatrix.a, mMatrix.b, mMatrix.c, mMatrix.d, mMatrix.tx, mMatrix.ty, ZDepth);
}
public void SetShaderConstantData(int slotIdx, void* data, int size)
public void SetVertexShaderConstantData(int slotIdx, void* data, int size)
{
Gfx_SetShaderConstantData((int32)slotIdx, data, (int32)size);
Gfx_SetShaderConstantData(0, (int32)slotIdx, data, (int32)size);
}
public void SetShaderConstantData(int32 slotIdx, void* data, ConstantDataDefinition constantDataDefinition)
public void SetPixelShaderConstantData(int slotIdx, void* data, int size)
{
Gfx_SetShaderConstantData(1, (int32)slotIdx, data, (int32)size);
}
public void SetVertexShaderConstantData(int32 slotIdx, void* data, ConstantDataDefinition constantDataDefinition)
{
int32* dataTypesPtr = (int32*)constantDataDefinition.mDataTypes.CArray();
Gfx_SetShaderConstantDataTyped(slotIdx, data, constantDataDefinition.mDataSize, dataTypesPtr, (int32)constantDataDefinition.mDataTypes.Count);
Gfx_SetShaderConstantDataTyped(0, slotIdx, data, constantDataDefinition.mDataSize, dataTypesPtr, (int32)constantDataDefinition.mDataTypes.Count);
}
public void SetShaderConstantData(int32 slotIdx, Matrix4 matrix)
public void SetVertexShaderConstantData(int32 slotIdx, Matrix4 matrix)
{
var mtx = matrix;
Gfx_SetShaderConstantData(0, slotIdx, &mtx, (int32)sizeof(Matrix4));
}
public void SetPixelShaderConstantData(int32 slotIdx, Matrix4 matrix)
{
var mtx = matrix;
Gfx_SetShaderConstantData(slotIdx, &mtx, (int32)sizeof(Matrix4));
Gfx_SetShaderConstantData(1, slotIdx, &mtx, (int32)sizeof(Matrix4));
}
public float DrawString(StringView theString, float x, float y, FontAlign alignment = FontAlign.Left, float width = 0, FontOverflowMode overflowMode = FontOverflowMode.Overflow, FontMetrics* fontMetrics = null)

View file

@ -90,15 +90,24 @@ namespace Beefy.gfx
public void* mNativeModelDef;
public float mFrameRate;
public int32 mJointCount;
public Animation[] mAnims;
public Dictionary<String, Animation> mAnimMap = new Dictionary<String, Animation>();
public Animation[] mAnims ~ DeleteContainerAndItems!(_);
public Dictionary<String, Animation> mAnimMap = new Dictionary<String, Animation>() ~ DeleteDictionaryAndKeys!(_);
[CallingConvention(.Stdcall), CLink]
extern static void* Res_OpenFBX(String fileName, void* nativeVertexDef);
extern static void* Res_OpenFBX(char8* fileName, void* nativeVertexDef);
[CallingConvention(.Stdcall), CLink]
extern static void* Res_OpenGLTF(char8* fileName, char8* baseDir, void* nativeVertexDef);
[CallingConvention(.Stdcall), CLink]
extern static void* Res_OpenModel(char8* fileName, char8* baseDir, void* nativeVertexDef);
[CallingConvention(.Stdcall), CLink]
extern static void* ModelDef_CreateModelInstance(void* nativeModel);
[CallingConvention(.Stdcall), CLink]
extern static char8* ModelDef_GetInfo(void* nativeModel);
[CallingConvention(.Stdcall), CLink]
extern static float ModelDef_GetFrameRate(void* nativeModel);
@ -111,6 +120,12 @@ namespace Beefy.gfx
[CallingConvention(.Stdcall), CLink]
extern static void* ModelDef_GetAnimation(void* nativeModel, int32 animIdx);
[CallingConvention(.Stdcall), CLink]
extern static void ModelDef_SetTextures(void* nativeModel, int32 meshIdx, int32 primitivesIdx, char8** paths, int32 pathCount);
[CallingConvention(.Stdcall), CLink]
extern static Span<uint8> Res_SerializeModel(void* nativeModel);
this(void* nativeModelDef)
{
mNativeModelDef = nativeModelDef;
@ -129,9 +144,15 @@ namespace Beefy.gfx
}
}
public static ModelDef LoadModel(String fileName)
public static ModelDef LoadModel(String fileName, String baseDir)
{
void* nativeModelDef = Res_OpenFBX(fileName, VertexDef.sVertexDefinition.mNativeVertexDefinition);
void* nativeModelDef = null;
if (fileName.EndsWith(".bfm", .OrdinalIgnoreCase))
nativeModelDef = Res_OpenModel(fileName, baseDir, VertexDef.sVertexDefinition.mNativeVertexDefinition);
else if (fileName.EndsWith(".fbx", .OrdinalIgnoreCase))
nativeModelDef = Res_OpenFBX(fileName, VertexDef.sVertexDefinition.mNativeVertexDefinition);
else
nativeModelDef = Res_OpenGLTF(fileName, baseDir, VertexDef.sVertexDefinition.mNativeVertexDefinition);
if (nativeModelDef == null)
return null;
return new ModelDef(nativeModelDef);
@ -150,6 +171,22 @@ namespace Beefy.gfx
{
return mAnimMap[name];
}
public void GetInfo(String str)
{
str.Append(ModelDef_GetInfo(mNativeModelDef));
}
public void SetTextures(int meshIdx, int primitivesIdx, Span<char8*> paths)
{
ModelDef_SetTextures(mNativeModelDef, (.)meshIdx, (.)primitivesIdx, paths.Ptr, (.)paths.Length);
}
public void Serialize(List<uint8> data)
{
var span = Res_SerializeModel(mNativeModelDef);
data.AddRange(span);
}
}
public class ModelInstance : RenderCmd

View file

@ -31,6 +31,9 @@ namespace Beefy.gfx
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetClip(void* renderState, float x, float y, float width, float height);
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetTexWrap(void* renderState, bool texWrap);
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_DisableClip(void* renderState);
@ -104,6 +107,14 @@ namespace Beefy.gfx
RenderState_DisableClip(mNativeRenderState);
}
}
public bool TexWrap
{
set
{
RenderState_SetTexWrap(mNativeRenderState, value);
}
}
}
#else
public class RenderState

View file

@ -410,7 +410,8 @@ namespace System
AppData_LocalLow,
AppData_Roaming,
Programs,
Programs_Common
Programs_Common,
Documents
}
public static Result<void, Platform.Result> GetStrHelper(String outStr, delegate void (char8* outPtr, int32* outSize, Result* outResult) func)

View file

@ -1,5 +1,35 @@
namespace System.Security.Cryptography
{
struct HashEncode
{
// Only 63 chars - skip zero
const char8[?] cHash64bToChar = .( 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_' );
public static void HashEncode64(uint64 val, String outStr)
{
var val;
if ((int64)val < 0)
{
uint64 flippedNum = (uint64)-(int64)val;
// Only flip if the encoded result would actually be shorter
if (flippedNum <= 0x00FFFFFFFFFFFFFFL)
{
val = flippedNum;
outStr.Append('_');
}
}
for (int i = 0; i < 10; i++)
{
int charIdx = (int)((val >> (i * 6)) & 0x3F) - 1;
if (charIdx != -1)
outStr.Append(cHash64bToChar[charIdx]);
}
}
}
struct MD5Hash
{
public uint8[16] mHash;
@ -50,6 +80,14 @@ namespace System.Security.Cryptography
val.ToString(strBuffer, "X2", null);
}
}
public void Encode(String outStr)
{
#unwarn
HashEncode.HashEncode64(((uint64*)&mHash)[0], outStr);
#unwarn
HashEncode.HashEncode64(((uint64*)&mHash)[1], outStr);
}
}
class MD5

View file

@ -643,14 +643,14 @@ BF_EXPORT void BF_CALLTYPE Gfx_DrawIndexedVertices2D(int vertexSize, void* vtxDa
}
}
BF_EXPORT void BF_CALLTYPE Gfx_SetShaderConstantData(int slotIdx, void* constData, int size)
BF_EXPORT void BF_CALLTYPE Gfx_SetShaderConstantData(int usageIdx, int slotIdx, void* constData, int size)
{
gBFApp->mRenderDevice->mCurDrawLayer->SetShaderConstantData(slotIdx, constData, size);
gBFApp->mRenderDevice->mCurDrawLayer->SetShaderConstantData(usageIdx, slotIdx, constData, size);
}
BF_EXPORT void BF_CALLTYPE Gfx_SetShaderConstantDataTyped(int slotIdx, void* constData, int size, int* typeData, int typeCount)
BF_EXPORT void BF_CALLTYPE Gfx_SetShaderConstantDataTyped(int usageIdx, int slotIdx, void* constData, int size, int* typeData, int typeCount)
{
gBFApp->mRenderDevice->mCurDrawLayer->SetShaderConstantDataTyped(slotIdx, constData, size, typeData, typeCount);
gBFApp->mRenderDevice->mCurDrawLayer->SetShaderConstantDataTyped(usageIdx, slotIdx, constData, size, typeData, typeCount);
}
BF_EXPORT void BF_CALLTYPE Gfx_QueueRenderCmd(RenderCmd* renderCmd)
@ -678,6 +678,11 @@ BF_EXPORT void BF_CALLTYPE RenderState_Delete(RenderState* renderState)
delete renderState;
}
BF_EXPORT void BF_CALLTYPE RenderState_SetTexWrap(RenderState* renderState, bool texWrap)
{
renderState->SetTexWrap(texWrap);
}
BF_EXPORT void BF_CALLTYPE RenderState_SetClip(RenderState* renderState, float x, float y, float width, float height)
{
BF_ASSERT((width >= 0) && (height >= 0));

View file

@ -445,6 +445,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClCompile Include="FileStream.cpp" />
<ClCompile Include="gfx\DrawLayer.cpp" />
<ClCompile Include="gfx\FTFont.cpp" />
<ClCompile Include="gfx\glTF.cpp" />
<ClCompile Include="gfx\ModelDef.cpp" />
<ClCompile Include="gfx\ModelInstance.cpp" />
<ClCompile Include="gfx\RenderCmd.cpp" />
@ -1933,6 +1934,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClCompile Include="util\CubicSpline.cpp" />
<ClCompile Include="util\Hash.cpp" />
<ClCompile Include="util\Heap.cpp" />
<ClCompile Include="util\Json.cpp" />
<ClCompile Include="util\MappedFile.cpp" />
<ClCompile Include="util\Matrix4.cpp" />
<ClCompile Include="util\PerfTimer.cpp" />
@ -1958,6 +1960,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClInclude Include="gfx\DrawLayer.h" />
<ClInclude Include="gfx\Font.h" />
<ClInclude Include="gfx\FTFont.h" />
<ClInclude Include="gfx\glTF.h" />
<ClInclude Include="gfx\ModelDef.h" />
<ClInclude Include="gfx\ModelInstance.h" />
<ClInclude Include="gfx\RenderCmd.h" />
@ -2161,6 +2164,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClInclude Include="util\Hash.h" />
<ClInclude Include="util\HashSet.h" />
<ClInclude Include="util\Heap.h" />
<ClInclude Include="util\Json.h" />
<ClInclude Include="util\MappedFile.h" />
<ClInclude Include="util\Matrix4.h" />
<ClInclude Include="util\MultiHashSet.h" />

View file

@ -707,6 +707,12 @@
<ClCompile Include="util\Heap.cpp">
<Filter>src\util</Filter>
</ClCompile>
<ClCompile Include="gfx\glTF.cpp">
<Filter>src\gfx</Filter>
</ClCompile>
<ClCompile Include="util\Json.cpp">
<Filter>src\util</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Common.h">
@ -1075,6 +1081,12 @@
<ClInclude Include="util\Heap.h">
<Filter>src\util</Filter>
</ClInclude>
<ClInclude Include="gfx\glTF.h">
<Filter>src\gfx</Filter>
</ClInclude>
<ClInclude Include="util\Json.h">
<Filter>src\util</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">

View file

@ -943,6 +943,21 @@ char* Beefy::LoadTextData(const StringImpl& path, int* size)
return data;
}
bool Beefy::LoadTextData(const StringImpl& path, StringImpl& str)
{
int size = 0;
char* data = LoadTextData(path, &size);
if (data == NULL)
return false;
if ((str.mAllocSizeAndFlags & StringImpl::DynAllocFlag) != 0)
str.Release();
str.mPtr = data;
str.mAllocSizeAndFlags = size | StringImpl::DynAllocFlag | StringImpl::StrPtrFlag;
str.mLength = size;
return true;
}
#ifdef BF_MINGW
unsigned long long __cdecl _byteswap_uint64(unsigned long long _Int64)
{
@ -1263,3 +1278,4 @@ void Beefy::BFFatalError(const char* message, const char* file, int line)
{
BFFatalError(String(message), String(file), line);
}

View file

@ -220,6 +220,7 @@ int32 GetHighestBitSet(int32 n);
uint8* LoadBinaryData(const StringImpl& path, int* size);
char* LoadTextData(const StringImpl& path, int* size);
bool LoadTextData(const StringImpl& path, StringImpl& str);
int64 GetFileTimeWrite(const StringImpl& path);
String GetFileDir(const StringImpl& path);
String GetFileName(const StringImpl& path);

View file

@ -49,6 +49,14 @@ public:
Read((void*) &val, sizeof(T));
}
template <typename T>
T ReadT()
{
T val;
Read((void*)&val, sizeof(T));
return val;
}
virtual void Write(float val);
virtual void Write(uint8 val);
virtual void Write(int8 val);

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;
std::vector<ModelVertex> mVertices;
std::vector<uint16> mIndices;
String mTexFileName;
String mBumpFileName;
//String mTexFileName;
//String mBumpFileName;
Array<ModelPrimitives> mPrimitives;
};
class ModelNode
{
public:
String mName;
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()

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;

View file

@ -49,7 +49,7 @@ bool TGAData::ReadData()
bool flipped = (hdr->mImageDescriptor & 0x20) != 0;
mWidth = hdr->mWidth;
mHeight = hdr->mWidth;
mHeight = hdr->mHeight;
mBits = new uint32[mWidth * mHeight];
if (hdr->mDataTypeCode == 10) // RLE
@ -148,6 +148,67 @@ readSpanHeader:
}
}
NOP;
}
else if (aMode == 3)
{
int y = 0;
int x = 0;
readSpanHeader3:
int spanLen = 0;
uint32 spanColor = 0;
uint8 spanHeader = *(srcPtr++);
spanLen = (spanHeader & 0x7F) + 1;
if ((spanHeader & 0x80) != 0)
{
// Repeat color
int b = *(srcPtr++);
int g = *(srcPtr++);
int r = *(srcPtr++);
int a = 255;
spanColor = (a << 24) | (b << 16) | (g << 8) | r;
for (; y < mHeight; y++)
{
for (; x < mWidth; x++)
{
if (spanLen == 0)
goto readSpanHeader3;
*(destPtr++) = spanColor;
spanLen--;
}
x = 0;
destPtr += destAdd;
}
}
else
{
for (; y < mHeight; y++)
{
for (; x < mWidth; x++)
{
if (spanLen == 0)
goto readSpanHeader3;
int b = *(srcPtr++);
int g = *(srcPtr++);
int r = *(srcPtr++);
int a = 255;
*(destPtr++) = (a << 24) | (b << 16) | (g << 8) | r;
spanLen--;
}
x = 0;
destPtr += destAdd;
}
}
NOP;
}
}

View file

@ -326,7 +326,8 @@ enum BfpSysDirectoryKind
BfpSysDirectoryKind_AppData_LocalLow,
BfpSysDirectoryKind_AppData_Roaming,
BfpSysDirectoryKind_Programs,
BfpSysDirectoryKind_Programs_Common
BfpSysDirectoryKind_Programs_Common,
BfpSysDirectoryKind_Documents
};
struct BfpFindFileData;

View file

@ -0,0 +1,243 @@
//--------------------------------------------------------------------------------------
// dds.h
//
// This header defines constants and structures that are useful when parsing
// DDS files. DDS files were originally designed to use several structures
// and constants that are native to DirectDraw and are defined in ddraw.h,
// such as DDSURFACEDESC2 and DDSCAPS2. This file defines similar
// (compatible) constants and structures so that one can use DDS files
// without needing to include ddraw.h.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// http://go.microsoft.com/fwlink/?LinkId=248926
//--------------------------------------------------------------------------------------
#pragma once
#if defined(_XBOX_ONE) && defined(_TITLE)
#include <d3d11_x.h>
#else
#include <dxgiformat.h>
#endif
#include <stdint.h>
namespace DirectX
{
#pragma pack(push,1)
const uint32_t DDS_MAGIC = 0x20534444; // "DDS "
struct DDS_PIXELFORMAT
{
uint32_t dwSize;
uint32_t dwFlags;
uint32_t dwFourCC;
uint32_t dwRGBBitCount;
uint32_t dwRBitMask;
uint32_t dwGBitMask;
uint32_t dwBBitMask;
uint32_t dwABitMask;
};
#define DDS_FOURCC 0x00000004 // DDPF_FOURCC
#define DDS_RGB 0x00000040 // DDPF_RGB
#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS
#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE
#define DDS_LUMINANCEA 0x00020001 // DDPF_LUMINANCE | DDPF_ALPHAPIXELS
#define DDS_ALPHA 0x00000002 // DDPF_ALPHA
#define DDS_PAL8 0x00000020 // DDPF_PALETTEINDEXED8
#define DDS_BUMPDUDV 0x00080000 // DDPF_BUMPDUDV
#ifndef MAKEFOURCC
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | \
((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24 ))
#endif /* defined(MAKEFOURCC) */
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT1 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT2 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT3 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT4 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DXT5 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC4_UNORM =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC4_SNORM =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC5_UNORM =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_BC5_SNORM =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R8G8_B8G8 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_G8R8_G8B8 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_YUY2 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8R8G8B8 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_X8R8G8B8 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8B8G8R8 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_X8B8G8R8 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_G16R16 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R5G6B5 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A1R5G5B5 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A4R4G4B4 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_R8G8B8 =
{ sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_L8 =
{ sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0xff, 0x00, 0x00, 0x00 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_L16 =
{ sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 16, 0xffff, 0x0000, 0x0000, 0x0000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8L8 =
{ sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0x00ff, 0x0000, 0x0000, 0xff00 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_A8 =
{ sizeof(DDS_PIXELFORMAT), DDS_ALPHA, 0, 8, 0x00, 0x00, 0x00, 0xff };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_V8U8 =
{ sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0x0000, 0x0000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_Q8W8V8U8 =
{ sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_V16U16 =
{ sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 };
// D3DFMT_A2R10G10B10/D3DFMT_A2B10G10R10 should be written using DX10 extension to avoid D3DX 10:10:10:2 reversal issue
// This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat)
extern __declspec(selectany) const DDS_PIXELFORMAT DDSPF_DX10 =
{ sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 };
#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT
#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH
#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH
#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE
#define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT
#define DDS_WIDTH 0x00000004 // DDSD_WIDTH
#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE
#define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX
#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ
#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\
DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\
DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ )
#define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP
#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME
// Subset here matches D3D10_RESOURCE_DIMENSION and D3D11_RESOURCE_DIMENSION
enum DDS_RESOURCE_DIMENSION
{
DDS_DIMENSION_TEXTURE1D = 2,
DDS_DIMENSION_TEXTURE2D = 3,
DDS_DIMENSION_TEXTURE3D = 4,
};
// Subset here matches D3D10_RESOURCE_MISC_FLAG and D3D11_RESOURCE_MISC_FLAG
enum DDS_RESOURCE_MISC_FLAG
{
DDS_RESOURCE_MISC_TEXTURECUBE = 0x4L,
};
enum DDS_MISC_FLAGS2
{
DDS_MISC_FLAGS2_ALPHA_MODE_MASK = 0x7L,
};
enum DDS_ALPHA_MODE
{
DDS_ALPHA_MODE_UNKNOWN = 0,
DDS_ALPHA_MODE_STRAIGHT = 1,
DDS_ALPHA_MODE_PREMULTIPLIED = 2,
DDS_ALPHA_MODE_OPAQUE = 3,
DDS_ALPHA_MODE_CUSTOM = 4,
};
struct DDS_HEADER
{
uint32_t dwSize;
uint32_t dwFlags;
uint32_t dwHeight;
uint32_t dwWidth;
uint32_t dwPitchOrLinearSize;
uint32_t dwDepth; // only if DDS_HEADER_FLAGS_VOLUME is set in dwFlags
uint32_t dwMipMapCount;
uint32_t dwReserved1[11];
DDS_PIXELFORMAT ddspf;
uint32_t dwCaps;
uint32_t dwCaps2;
uint32_t dwCaps3;
uint32_t dwCaps4;
uint32_t dwReserved2;
};
struct DDS_HEADER_DXT10
{
DXGI_FORMAT dxgiFormat;
uint32_t resourceDimension;
uint32_t miscFlag; // see DDS_RESOURCE_MISC_FLAG
uint32_t arraySize;
uint32_t miscFlags2; // see DDS_MISC_FLAGS2
};
#pragma pack(pop)
static_assert( sizeof(DDS_HEADER) == 124, "DDS Header size mismatch" );
static_assert( sizeof(DDS_HEADER_DXT10) == 20, "DDS DX10 Extended Header size mismatch");
}; // namespace

View file

@ -5,6 +5,10 @@
#include "img/ImageData.h"
#include "util/PerfTimer.h"
#include "util/BeefPerf.h"
#include "FileStream.h"
#include "DDS.h"
using namespace DirectX;
#include <D3Dcompiler.h>
@ -37,6 +41,131 @@ USING_NS_BF;
#define DXFAILED(check) ((hr = (check)) != 0)
#define DXCHECK(check) if ((check) != 0) BF_FATAL(StrFormat("DirectX call failed with result 0x%X", check).c_str());
static int GetBytesPerPixel(DXGI_FORMAT fmt, int& blockSize)
{
blockSize = 1;
switch (fmt)
{
case DXGI_FORMAT_UNKNOWN: return 0;
case DXGI_FORMAT_R32G32B32A32_TYPELESS: return 4 + 4 + 4 + 4;
case DXGI_FORMAT_R32G32B32A32_FLOAT: return 4 + 4 + 4 + 4;
case DXGI_FORMAT_R32G32B32A32_UINT: return 4 + 4 + 4 + 4;
case DXGI_FORMAT_R32G32B32A32_SINT: return 4 + 4 + 4 + 4;
case DXGI_FORMAT_R32G32B32_TYPELESS: return 4 + 4 + 4;
case DXGI_FORMAT_R32G32B32_FLOAT: return 4 + 4 + 4;
case DXGI_FORMAT_R32G32B32_UINT: return 4 + 4 + 4;
case DXGI_FORMAT_R32G32B32_SINT: return 4 + 4 + 4;
case DXGI_FORMAT_R16G16B16A16_TYPELESS: return 2 + 2 + 2 + 2;
case DXGI_FORMAT_R16G16B16A16_FLOAT: return 2 + 2 + 2 + 2;
case DXGI_FORMAT_R16G16B16A16_UNORM: return 2 + 2 + 2 + 2;
case DXGI_FORMAT_R16G16B16A16_UINT: return 2 + 2 + 2 + 2;
case DXGI_FORMAT_R16G16B16A16_SNORM: return 2 + 2 + 2 + 2;
case DXGI_FORMAT_R16G16B16A16_SINT: return 2 + 2 + 2 + 2;
case DXGI_FORMAT_R32G32_TYPELESS: return 4 + 4;
case DXGI_FORMAT_R32G32_FLOAT: return 4 + 4;
case DXGI_FORMAT_R32G32_UINT: return 4 + 4;
case DXGI_FORMAT_R32G32_SINT: return 4 + 4;
case DXGI_FORMAT_R32G8X24_TYPELESS: return 4 + 3;
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return 4 + 1 + 3;
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: return 4 + 1 + 3;
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: return 4 + 1 + 1 + 3;
case DXGI_FORMAT_R10G10B10A2_TYPELESS: return 4;
case DXGI_FORMAT_R10G10B10A2_UNORM: return 4;
case DXGI_FORMAT_R10G10B10A2_UINT: return 4;
case DXGI_FORMAT_R11G11B10_FLOAT: return 4;
case DXGI_FORMAT_R8G8B8A8_TYPELESS: return 4;
case DXGI_FORMAT_R8G8B8A8_UNORM: return 4;
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return 4;
case DXGI_FORMAT_R8G8B8A8_UINT: return 4;
case DXGI_FORMAT_R8G8B8A8_SNORM: return 4;
case DXGI_FORMAT_R8G8B8A8_SINT: return 4;
case DXGI_FORMAT_R16G16_TYPELESS: return 4;
case DXGI_FORMAT_R16G16_FLOAT: return 4;
case DXGI_FORMAT_R16G16_UNORM: return 4;
case DXGI_FORMAT_R16G16_UINT: return 4;
case DXGI_FORMAT_R16G16_SNORM: return 4;
case DXGI_FORMAT_R16G16_SINT: return 4;
case DXGI_FORMAT_R32_TYPELESS: return 4;
case DXGI_FORMAT_D32_FLOAT: return 4;
case DXGI_FORMAT_R32_FLOAT: return 4;
case DXGI_FORMAT_R32_UINT: return 4;
case DXGI_FORMAT_R32_SINT: return 4;
case DXGI_FORMAT_R24G8_TYPELESS: return 4;
case DXGI_FORMAT_D24_UNORM_S8_UINT: return 4;
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: return 4;
case DXGI_FORMAT_X24_TYPELESS_G8_UINT: return 4;
case DXGI_FORMAT_R8G8_TYPELESS: return 2;
case DXGI_FORMAT_R8G8_UNORM: return 2;
case DXGI_FORMAT_R8G8_UINT: return 2;
case DXGI_FORMAT_R8G8_SNORM: return 2;
case DXGI_FORMAT_R8G8_SINT: return 2;
case DXGI_FORMAT_R16_TYPELESS: return 2;
case DXGI_FORMAT_R16_FLOAT: return 2;
case DXGI_FORMAT_D16_UNORM: return 2;
case DXGI_FORMAT_R16_UNORM: return 2;
case DXGI_FORMAT_R16_UINT: return 2;
case DXGI_FORMAT_R16_SNORM: return 2;
case DXGI_FORMAT_R16_SINT: return 2;
case DXGI_FORMAT_R8_TYPELESS: return 1;
case DXGI_FORMAT_R8_UNORM: return 1;
case DXGI_FORMAT_R8_UINT: return 1;
case DXGI_FORMAT_R8_SNORM: return 1;
case DXGI_FORMAT_R8_SINT: return 1;
case DXGI_FORMAT_A8_UNORM: return 1;
case DXGI_FORMAT_R1_UNORM: return 1;
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: return 3;
case DXGI_FORMAT_R8G8_B8G8_UNORM: return 4;
case DXGI_FORMAT_G8R8_G8B8_UNORM: return 4;
case DXGI_FORMAT_BC1_TYPELESS: blockSize = 4; return 8;
case DXGI_FORMAT_BC1_UNORM: blockSize = 4; return 8;
case DXGI_FORMAT_BC1_UNORM_SRGB: blockSize = 4; return 8;
case DXGI_FORMAT_BC2_TYPELESS: blockSize = 4; return 16;
case DXGI_FORMAT_BC2_UNORM: blockSize = 4; return 16;
case DXGI_FORMAT_BC2_UNORM_SRGB: blockSize = 4; return 16;
case DXGI_FORMAT_BC3_TYPELESS: blockSize = 4; return 16;
case DXGI_FORMAT_BC3_UNORM: blockSize = 4; return 16;
case DXGI_FORMAT_BC3_UNORM_SRGB: blockSize = 4; return 16;
case DXGI_FORMAT_BC4_TYPELESS: blockSize = 4; return 8;
case DXGI_FORMAT_BC4_UNORM: blockSize = 4; return 8;
case DXGI_FORMAT_BC4_SNORM: blockSize = 4; return 8;
case DXGI_FORMAT_BC5_TYPELESS: blockSize = 4; return 16;
case DXGI_FORMAT_BC5_UNORM: blockSize = 4; return 16;
case DXGI_FORMAT_BC5_SNORM: blockSize = 4; return 16;
case DXGI_FORMAT_B5G6R5_UNORM: return 1;
case DXGI_FORMAT_B5G5R5A1_UNORM: return 2;
case DXGI_FORMAT_B8G8R8A8_UNORM: return 4;
case DXGI_FORMAT_B8G8R8X8_UNORM: return 4;
case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: return 4;
case DXGI_FORMAT_B8G8R8A8_TYPELESS: return 4;
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return 4;
case DXGI_FORMAT_B8G8R8X8_TYPELESS: return 4;
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return 4;
case DXGI_FORMAT_BC6H_TYPELESS: return 1;
case DXGI_FORMAT_BC6H_UF16: return 1;
case DXGI_FORMAT_BC6H_SF16: return 1;
case DXGI_FORMAT_BC7_TYPELESS: return 1;
case DXGI_FORMAT_BC7_UNORM: return 1;
case DXGI_FORMAT_BC7_UNORM_SRGB: return 1;
case DXGI_FORMAT_AYUV: return 1;
case DXGI_FORMAT_Y410: return 1;
case DXGI_FORMAT_Y416: return 1;
case DXGI_FORMAT_NV12: return 1;
case DXGI_FORMAT_P010: return 1;
case DXGI_FORMAT_P016: return 1;
case DXGI_FORMAT_420_OPAQUE: return 1;
case DXGI_FORMAT_YUY2: return 1;
case DXGI_FORMAT_Y210: return 1;
case DXGI_FORMAT_Y216: return 1;
case DXGI_FORMAT_NV11: return 1;
case DXGI_FORMAT_AI44: return 1;
case DXGI_FORMAT_IA44: return 1;
case DXGI_FORMAT_P8: return 1;
case DXGI_FORMAT_A8P8: return 1;
case DXGI_FORMAT_B4G4R4A4_UNORM: return 1;
default: return 1;
}
}
DXShaderParam::DXShaderParam()
{
mD3DVariable = NULL;
@ -383,7 +512,7 @@ void DXRenderDevice::PhysSetRenderState(RenderState* renderState)
if ((renderState->mShader != mPhysRenderState->mShader) && (renderState->mShader != NULL))
{
mD3DDeviceContext->PSSetSamplers(0, 1, &mD3DDefaultSamplerState);
mD3DDeviceContext->PSSetSamplers(0, 1, mPhysRenderState->mTexWrap ? &mD3DWrapSamplerState : &mD3DDefaultSamplerState);
mD3DDeviceContext->IASetInputLayout(dxShader->mD3DLayout);
mD3DDeviceContext->VSSetShader(dxShader->mD3DVertexShader, NULL, 0);
mD3DDeviceContext->PSSetShader(dxShader->mD3DPixelShader, NULL, 0);
@ -595,6 +724,7 @@ ModelInstance* DXRenderDevice::CreateModelInstance(ModelDef* modelDef)
//renderState->mCullMode = CullMode_Front;
renderState->mTexWrap = true;
renderState->mDepthFunc = DepthFunc_LessEqual;
renderState->mWriteDepthBuffer = true;
@ -603,90 +733,134 @@ ModelInstance* DXRenderDevice::CreateModelInstance(ModelDef* modelDef)
////
dxModelInstance->mD3DRenderDevice = this;
dxModelInstance->mDXModelMeshs.resize(modelDef->mMeshes.size());
dxModelInstance->mDXModelMeshs.Resize(modelDef->mMeshes.size());
int dxMeshIdx = 0;
for (int meshIdx = 0; meshIdx < (int)modelDef->mMeshes.size(); meshIdx++)
{
ModelMesh* mesh = &modelDef->mMeshes[meshIdx];
DXModelMesh* dxMesh = &dxModelInstance->mDXModelMeshs[dxMeshIdx];
DXModelMesh* dxMesh = &dxModelInstance->mDXModelMeshs[meshIdx];
dxMesh->mPrimitives.Resize(mesh->mPrimitives.size());
String texPath = mesh->mTexFileName;
if ((int)texPath.IndexOf(':') == -1)
texPath = modelDef->mLoadDir + "Textures/" + texPath;
//texPath = gBFApp->mInstallDir + L"models/Textures/" + texPath;
dxMesh->mTexture = (DXTexture*)((RenderDevice*)this)->LoadTexture(texPath, TextureFlag_NoPremult);
dxMesh->mNumIndices = (int)mesh->mIndices.size();
dxMesh->mNumVertices = (int)mesh->mVertices.size();
D3D11_BUFFER_DESC bd;
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = (int)mesh->mIndices.size() * sizeof(uint16);
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;
bd.StructureByteStride = 0;
mD3DDevice->CreateBuffer(&bd, NULL, &dxMesh->mD3DIndexBuffer);
D3D11_MAPPED_SUBRESOURCE mappedSubResource;
DXCHECK(mD3DDeviceContext->Map(dxMesh->mD3DIndexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubResource));
uint16* dxIdxData = (uint16*)mappedSubResource.pData;
for (int idxIdx = 0; idxIdx < dxMesh->mNumIndices; idxIdx++)
dxIdxData[idxIdx] = (uint16)mesh->mIndices[idxIdx];
mD3DDeviceContext->Unmap(dxMesh->mD3DIndexBuffer, 0);
//
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = (int)mesh->mVertices.size() * sizeof(DXModelVertex);
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;
bd.StructureByteStride = 0;
mD3DDevice->CreateBuffer(&bd, NULL, &dxMesh->mD3DVertexBuffer);
/*DXCHECK(mD3DDeviceContext->Map(dxMesh->mD3DVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubResource));
DXModelVertex* dxVtxData = (DXModelVertex*)mappedSubResource.pData;
for (int vtxIdx = 0; vtxIdx < (int)mesh->mVertexData.size(); vtxIdx++)
for (int primitivesIdx = 0 ; primitivesIdx < (int)mesh->mPrimitives.size(); primitivesIdx++)
{
VertexData* srcVtxData = &mesh->mVertexData[vtxIdx];
DXModelVertex* destVtx = dxVtxData + vtxIdx;
auto primitives = &mesh->mPrimitives[primitivesIdx];
auto dxPrimitives = &dxMesh->mPrimitives[primitivesIdx];
destVtx->mPosition = srcVtxData->mCoords;
destVtx->mTexCoords = srcVtxData->mTexCoords[0];
destVtx->mTexCoords.mV = 1.0f - destVtx->mTexCoords.mV;
destVtx->mBumpTexCoords = srcVtxData->mTexCoords[0];
destVtx->mColor = 0xFFFFFFFF;
destVtx->mTangent = srcVtxData->mTangent;
// String texPath = mesh->mTexFileName;
// if (!texPath.IsEmpty())
// {
// if ((int)texPath.IndexOf(':') == -1)
// texPath = modelDef->mLoadDir + "Textures/" + texPath;
// //texPath = gBFApp->mInstallDir + L"models/Textures/" + texPath;
//
// dxPrimitives->mTexture = (DXTexture*)((RenderDevice*)this)->LoadTexture(texPath, TextureFlag_NoPremult);
// }
Array<String> texPaths = primitives->mTexPaths;
if (primitives->mMaterial != NULL)
{
dxPrimitives->mMaterialName = primitives->mMaterial->mName;
if (primitives->mMaterial->mDef != NULL)
{
for (auto& texParamVal : primitives->mMaterial->mDef->mTextureParameterValues)
{
if (texPaths.IsEmpty())
texPaths.Add(texParamVal->mTexturePath);
// if (texPath.IsEmpty())
// texPath = texParamVal->mTexturePath;
// if ((texParamVal->mName == "Albedo_texture") || (texParamVal->mName.EndsWith("_Color")))
// texPath = texParamVal->mTexturePath;
// else if ((texParamVal->mName == "NM_texture") || (texParamVal->mName.EndsWith("_NM")))
// bumpTexPath = texParamVal->mTexturePath;
}
}
}
for (auto& texPath : texPaths)
{
if (!modelDef->mLoadDir.IsEmpty())
texPath = GetAbsPath(texPath, modelDef->mLoadDir);
dxPrimitives->mTextures.Add((DXTexture*)((RenderDevice*)this)->LoadTexture(texPath, TextureFlag_NoPremult));
}
dxPrimitives->mNumIndices = (int)primitives->mIndices.size();
dxPrimitives->mNumVertices = (int)primitives->mVertices.size();
D3D11_BUFFER_DESC bd;
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = (int)primitives->mIndices.size() * sizeof(uint16);
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;
bd.StructureByteStride = 0;
mD3DDevice->CreateBuffer(&bd, NULL, &dxPrimitives->mD3DIndexBuffer);
D3D11_MAPPED_SUBRESOURCE mappedSubResource;
DXCHECK(mD3DDeviceContext->Map(dxPrimitives->mD3DIndexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubResource));
uint16* dxIdxData = (uint16*)mappedSubResource.pData;
for (int idxIdx = 0; idxIdx < dxPrimitives->mNumIndices; idxIdx++)
dxIdxData[idxIdx] = (uint16)primitives->mIndices[idxIdx];
mD3DDeviceContext->Unmap(dxPrimitives->mD3DIndexBuffer, 0);
//
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = (int)primitives->mVertices.size() * sizeof(DXModelVertex);
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;
bd.StructureByteStride = 0;
mD3DDevice->CreateBuffer(&bd, NULL, &dxPrimitives->mD3DVertexBuffer);
DXCHECK(mD3DDeviceContext->Map(dxPrimitives->mD3DVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubResource));
DXModelVertex* dxVtxData = (DXModelVertex*)mappedSubResource.pData;
for (int vtxIdx = 0; vtxIdx < (int)primitives->mVertices.size(); vtxIdx++)
{
ModelVertex* srcVtxData = &primitives->mVertices[vtxIdx];
DXModelVertex* destVtx = dxVtxData + vtxIdx;
destVtx->mPosition = srcVtxData->mPosition;
destVtx->mTexCoords = srcVtxData->mTexCoords;
//destVtx->mTexCoords.mV = 1.0f - destVtx->mTexCoords.mV;
destVtx->mTexCoords.mV = destVtx->mTexCoords.mV;
destVtx->mBumpTexCoords = srcVtxData->mBumpTexCoords;
destVtx->mColor = srcVtxData->mColor;
destVtx->mTangent = srcVtxData->mTangent;
}
mD3DDeviceContext->Unmap(dxPrimitives->mD3DVertexBuffer, 0);
dxMeshIdx++;
}
mD3DDeviceContext->Unmap(dxMesh->mD3DVertexBuffer, 0);*/
}
return dxModelInstance;
}
void DXDrawLayer::SetShaderConstantData(int slotIdx, void* constData, int size)
void DXDrawLayer::SetShaderConstantData(int usageIdx, int slotIdx, void* constData, int size)
{
DXSetConstantData* dxSetConstantData = AllocRenderCmd<DXSetConstantData>(size);
dxSetConstantData->mRenderState = mRenderDevice->mCurRenderState;
dxSetConstantData->mUsageIdx = usageIdx;
dxSetConstantData->mSlotIdx = slotIdx;
dxSetConstantData->mSize = size;
if (size == 64) // Transpose for shader
*((Matrix4*)dxSetConstantData->mData) = Matrix4::Transpose(*((Matrix4*)constData));
else
// if (size == 64) // Transpose for shader
// *((Matrix4*)dxSetConstantData->mData) = Matrix4::Transpose(*((Matrix4*)constData));
// else
memcpy(dxSetConstantData->mData, constData, size);
QueueRenderCmd(dxSetConstantData);
}
void DXDrawLayer::SetShaderConstantDataTyped(int slotIdx, void* constData, int size, int* typeData, int typeCount)
void DXDrawLayer::SetShaderConstantDataTyped(int usageIdx, int slotIdx, void* constData, int size, int* typeData, int typeCount)
{
for (int usageIdx = 0; usageIdx < 2; usageIdx++)
{
@ -770,18 +944,20 @@ void DXDrawLayer::SetShaderConstantDataTyped(int slotIdx, void* constData, int s
///
DXModelMesh::DXModelMesh()
DXModelPrimitives::DXModelPrimitives()
{
mD3DIndexBuffer = NULL;
mD3DVertexBuffer = NULL;
}
DXModelMesh::~DXModelMesh()
DXModelPrimitives::~DXModelPrimitives()
{
if (mD3DIndexBuffer != NULL)
mD3DIndexBuffer->Release();
if (mD3DVertexBuffer != NULL)
mD3DVertexBuffer->Release();
for (auto tex : mTextures)
tex->Release();
}
//////////////////////////////////////////////////////////////////////////
@ -839,6 +1015,12 @@ void DXRenderState::SetClipped(bool clipped)
InvalidateRasterizerState();
}
void DXRenderState::SetTexWrap(bool wrap)
{
mTexWrap = wrap;
InvalidateRasterizerState();
}
void DXRenderState::SetClipRect(const Rect& rect)
{
BF_ASSERT((rect.mWidth >= 0) && (rect.mHeight >= 0));
@ -879,14 +1061,44 @@ void DXModelInstance::Render(RenderDevice* renderDevice, RenderWindow* renderWin
DXModelMesh* dxMesh = &mDXModelMeshs[meshIdx];
mD3DRenderDevice->mD3DDeviceContext->PSSetShaderResources(0, 1, &dxMesh->mTexture->mD3DResourceView);
for (auto primIdx = 0; primIdx < (int)dxMesh->mPrimitives.size(); primIdx++)
{
auto dxPrimitives = &dxMesh->mPrimitives[primIdx];
// Set vertex buffer
UINT stride = sizeof(DXModelVertex);
UINT offset = 0;
mD3DRenderDevice->mD3DDeviceContext->IASetVertexBuffers(0, 1, &dxMesh->mD3DVertexBuffer, &stride, &offset);
mD3DRenderDevice->mD3DDeviceContext->IASetIndexBuffer(dxMesh->mD3DIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
mD3DRenderDevice->mD3DDeviceContext->DrawIndexed(dxMesh->mNumIndices, 0, 0);
if (dxPrimitives->mNumIndices == 11904)
{
NOP;
}
//TODO:
if (dxPrimitives->mNumIndices == 48384)
continue;
if (::GetAsyncKeyState('1'))
{
if (dxPrimitives->mNumIndices != 9417)
continue;
}
else if (::GetAsyncKeyState('2'))
{
if (dxPrimitives->mNumIndices != 3684)
continue;
}
if (dxPrimitives->mTextures.IsEmpty())
continue;
for (int i = 0; i < (int)dxPrimitives->mTextures.mSize; i++)
mD3DRenderDevice->mD3DDeviceContext->PSSetShaderResources(i, 1, &dxPrimitives->mTextures[i]->mD3DResourceView);
// Set vertex buffer
UINT stride = sizeof(DXModelVertex);
UINT offset = 0;
mD3DRenderDevice->mD3DDeviceContext->IASetVertexBuffers(0, 1, &dxPrimitives->mD3DVertexBuffer, &stride, &offset);
mD3DRenderDevice->mD3DDeviceContext->IASetIndexBuffer(dxPrimitives->mD3DIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
mD3DRenderDevice->mD3DDeviceContext->DrawIndexed(dxPrimitives->mNumIndices, 0, 0);
}
}
}
@ -992,46 +1204,59 @@ void DXSetTextureCmd::Render(RenderDevice* renderDevice, RenderWindow* renderWin
void DXSetConstantData::Render(RenderDevice* renderDevice, RenderWindow* renderWindow)
{
SetRenderState();
//SetRenderState();
DXShader* dxShader = (DXShader*)renderDevice->mCurRenderState->mShader;
DXRenderDevice* dxRenderDevice = (DXRenderDevice*)renderDevice;
HRESULT result = 0;
int numBlocks = (mSize + 16 - 1) / 16;
int mtxBufferNum = mSlotIdx * 32 + (numBlocks - 1) * 2 + mUsageIdx;
static ID3D11Buffer* matrixBuffers[32 * 32 * 2] = {NULL};
int bufferSize = BF_ALIGN(mSize, 16);
if (matrixBuffers[mtxBufferNum] == NULL)
int id = (mSlotIdx << 24) | (bufferSize << 1) | (mUsageIdx);
ID3D11Buffer* buffer = NULL;
ID3D11Buffer** bufferPtr = NULL;
if (dxRenderDevice->mBufferMap.TryAdd(id, NULL, &bufferPtr))
{
D3D11_BUFFER_DESC matrixBufferDesc;
matrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
matrixBufferDesc.ByteWidth = sizeof(float[4]) * numBlocks;
matrixBufferDesc.ByteWidth = bufferSize;
matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
matrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
matrixBufferDesc.MiscFlags = 0;
matrixBufferDesc.StructureByteStride = 0;
result = dxRenderDevice->mD3DDevice->CreateBuffer(&matrixBufferDesc, NULL, &matrixBuffers[mtxBufferNum]);
result = dxRenderDevice->mD3DDevice->CreateBuffer(&matrixBufferDesc, NULL, &buffer);
if (FAILED(result))
return;
//OutputDebugStrF("Created Buffer %d %p\n", bufferSize, buffer);
*bufferPtr = buffer;
}
else
buffer = *bufferPtr;
D3D11_MAPPED_SUBRESOURCE mappedResource;
result = dxRenderDevice->mD3DDeviceContext->Map(matrixBuffers[mtxBufferNum], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
result = dxRenderDevice->mD3DDeviceContext->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
return;
float* dataPtr = (float*) mappedResource.pData;
memset(dataPtr, 0, numBlocks * 16);
float* dataPtr = (float*)mappedResource.pData;
memset(dataPtr, 0, bufferSize);
memcpy(mappedResource.pData, mData, mSize);
dxRenderDevice->mD3DDeviceContext->Unmap(matrixBuffers[mtxBufferNum], 0);
dxRenderDevice->mD3DDeviceContext->Unmap(buffer, 0);
if (mUsageIdx == 0)
dxRenderDevice->mD3DDeviceContext->VSSetConstantBuffers(mSlotIdx, 1, &matrixBuffers[mtxBufferNum]);
{
//OutputDebugStrF("VSSetConstantBuffers %d %p\n", mSlotIdx, buffer);
dxRenderDevice->mD3DDeviceContext->VSSetConstantBuffers(mSlotIdx, 1, &buffer);
}
else
dxRenderDevice->mD3DDeviceContext->PSSetConstantBuffers(mSlotIdx, 1, &matrixBuffers[mtxBufferNum]);
{
//OutputDebugStrF("PSSetConstantBuffers %d %p\n", mSlotIdx, buffer);
dxRenderDevice->mD3DDeviceContext->PSSetConstantBuffers(mSlotIdx, 1, &buffer);
}
}
///
@ -1291,7 +1516,8 @@ bool DXRenderDevice::Init(BFApp* app)
D3D_FEATURE_LEVEL d3dFeatureLevel = (D3D_FEATURE_LEVEL)0;
int flags = 0;
//flags = D3D11_CREATE_DEVICE_DEBUG;
//TODO:
flags = D3D11_CREATE_DEVICE_DEBUG;
DXCHECK(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, featureLevelArr, 6, D3D11_SDK_VERSION, &mD3DDevice, &d3dFeatureLevel, &mD3DDeviceContext));
OutputDebugStrF("D3D Feature Level: %X\n", d3dFeatureLevel);
@ -1364,9 +1590,18 @@ bool DXRenderDevice::Init(BFApp* app)
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
DXCHECK(mD3DDevice->CreateSamplerState(&sampDesc, &mD3DDefaultSamplerState));
ZeroMemory(&sampDesc, sizeof(sampDesc));
sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
DXCHECK(mD3DDevice->CreateSamplerState(&sampDesc, &mD3DWrapSamplerState));
D3D11_BUFFER_DESC bd;
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = DX_VTXBUFFER_SIZE;
@ -1402,6 +1637,8 @@ void DXRenderDevice::ReleaseNative()
mD3DNormalBlendState = NULL;
mD3DDefaultSamplerState->Release();
mD3DDefaultSamplerState = NULL;
mD3DWrapSamplerState->Release();
mD3DWrapSamplerState = NULL;
mD3DDeviceContext->Release();
mD3DDeviceContext = NULL;
mD3DDevice->Release();
@ -1468,6 +1705,178 @@ void DXRenderDevice::FrameEnd()
}
}
Texture* DXRenderDevice::LoadTexture(const StringImpl& fileName, int flags)
{
if (fileName.StartsWith("!backbuffer:"))
{
int colon = (int)fileName.IndexOf(':');
String addrStr = fileName.Substring(colon + 1);
void* addr = (void*)(intptr)strtoll(addrStr.c_str(), NULL, 16);
BFWindow* window = (BFWindow*)addr;
DXRenderWindow* renderWindow = (DXRenderWindow*)window->mRenderWindow;
DXTexture* aTexture = NULL;
aTexture->mD3DRenderTargetView = renderWindow->mD3DRenderTargetView;
aTexture->mD3DTexture = renderWindow->mD3DBackBuffer;
aTexture->mD3DRenderTargetView->AddRef();
aTexture->mD3DTexture->AddRef();
aTexture->AddRef();
return aTexture;
}
DXTexture* aTexture = NULL;
if (mTextureMap.TryGetValue(fileName, &aTexture))
{
aTexture->AddRef();
return aTexture;
}
int dotPos = (int)fileName.LastIndexOf('.');
String ext;
if (dotPos != -1)
ext = fileName.Substring(dotPos);
if (ext.Equals(".dds", StringImpl::CompareKind_OrdinalIgnoreCase))
{
FileStream fs;
if (!fs.Open(fileName, "rb"))
return NULL;
int header = fs.ReadInt32();
if (header != 0x20534444)
return NULL;
auto hdr = fs.ReadT<DDS_HEADER>();
DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
if (hdr.ddspf.dwFlags == DDS_RGBA)
{
if (hdr.ddspf.dwRGBBitCount == 32)
{
if (hdr.ddspf.dwRBitMask == 0xff)
format = DXGI_FORMAT_R8G8B8A8_UNORM;
else if (hdr.ddspf.dwRBitMask = 0xff0000)
format = DXGI_FORMAT_B8G8R8A8_UNORM;
else if (hdr.ddspf.dwRBitMask == 0xffff)
format = DXGI_FORMAT_R16G16_UNORM;
else if (hdr.ddspf.dwRBitMask == 0x3ff)
format = DXGI_FORMAT_R10G10B10A2_UNORM;
}
else if (hdr.ddspf.dwRGBBitCount == 16)
{
if (hdr.ddspf.dwRBitMask == 0x7c00)
format = DXGI_FORMAT_B5G5R5A1_UNORM;
else if (hdr.ddspf.dwRBitMask == 0xf800)
format = DXGI_FORMAT_B5G6R5_UNORM;
}
else if (hdr.ddspf.dwRGBBitCount == 8)
{
if (hdr.ddspf.dwRBitMask == 0xff)
format = DXGI_FORMAT_R8_UNORM;
else if (hdr.ddspf.dwABitMask == 0xff)
format = DXGI_FORMAT_A8_UNORM;
}
}
if (hdr.ddspf.dwFourCC == '1TXD')
format = DXGI_FORMAT_BC1_UNORM;
if (hdr.ddspf.dwFourCC == '3TXD')
format = DXGI_FORMAT_BC2_UNORM;
if (hdr.ddspf.dwFourCC == '5TXD')
format = DXGI_FORMAT_BC3_UNORM;
if (hdr.ddspf.dwFourCC == 'U4CB')
format = DXGI_FORMAT_BC4_UNORM;
if (hdr.ddspf.dwFourCC == 'S4CB')
format = DXGI_FORMAT_BC4_SNORM;
if (hdr.ddspf.dwFourCC == '2ITA')
format = DXGI_FORMAT_BC5_UNORM;
if (hdr.ddspf.dwFourCC == 'S5CB')
format = DXGI_FORMAT_BC5_SNORM;
if (hdr.ddspf.dwFourCC == '01XD')
{
auto hdr10 = fs.ReadT<DDS_HEADER_DXT10>();
format = hdr10.dxgiFormat;
}
int blockSize = 0;
int bytesPerPixel = GetBytesPerPixel(format, blockSize);
int mipSize = ((hdr.dwWidth + blockSize - 1) / blockSize) * ((hdr.dwHeight + blockSize - 1) / blockSize) * bytesPerPixel;
Array<uint8> data;
data.Resize(mipSize);
fs.Read(data.mVals, data.mSize);
D3D11_SUBRESOURCE_DATA resData;
resData.pSysMem = data.mVals;
resData.SysMemPitch = ((hdr.dwWidth + blockSize - 1) / blockSize) * bytesPerPixel;
resData.SysMemSlicePitch = mipSize;
// Create the target texture
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = hdr.dwWidth;
desc.Height = hdr.dwHeight;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = format;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.CPUAccessFlags = 0;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
DXGI_FORMAT viewFormat = format;
switch (viewFormat)
{
case DXGI_FORMAT_B8G8R8A8_TYPELESS: viewFormat = DXGI_FORMAT_B8G8R8A8_UNORM; break;
case DXGI_FORMAT_R8G8B8A8_TYPELESS: viewFormat = DXGI_FORMAT_R8G8B8A8_UNORM; break;
case DXGI_FORMAT_BC1_TYPELESS: viewFormat = DXGI_FORMAT_BC1_UNORM; break;
case DXGI_FORMAT_BC2_TYPELESS: viewFormat = DXGI_FORMAT_BC2_UNORM; break;
case DXGI_FORMAT_BC3_TYPELESS: viewFormat = DXGI_FORMAT_BC3_UNORM; break;
case DXGI_FORMAT_BC4_TYPELESS: viewFormat = DXGI_FORMAT_BC4_UNORM; break;
case DXGI_FORMAT_BC5_TYPELESS: viewFormat = DXGI_FORMAT_BC5_UNORM; break;
}
//OutputDebugStrF("Creating texture\n");
ID3D11Texture2D* d3DTexture = NULL;
DXCHECK(mD3DDevice->CreateTexture2D(&desc, &resData, &d3DTexture));
D3D11_SHADER_RESOURCE_VIEW_DESC srDesc;
srDesc.Format = viewFormat;
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = 1;
ID3D11ShaderResourceView* d3DShaderResourceView = NULL;
DXCHECK(mD3DDevice->CreateShaderResourceView(d3DTexture, &srDesc, &d3DShaderResourceView));
DXTexture* aTexture = new DXTexture();
aTexture->mPath = fileName;
aTexture->mRenderDevice = this;
aTexture->mWidth = hdr.dwWidth;
aTexture->mHeight = hdr.dwHeight;
aTexture->mD3DTexture = d3DTexture;
aTexture->mD3DResourceView = d3DShaderResourceView;
aTexture->AddRef();
mTextureMap[aTexture->mPath] = aTexture;
mTextures.Add(aTexture);
return aTexture;
}
aTexture = (DXTexture*)RenderDevice::LoadTexture(fileName, flags);
if (aTexture != NULL)
{
aTexture->mPath = fileName;
mTextureMap[aTexture->mPath] = aTexture;
}
return aTexture;
}
Texture* DXRenderDevice::LoadTexture(ImageData* imageData, int flags)
{
ID3D11ShaderResourceView* d3DShaderResourceView = NULL;
@ -1833,6 +2242,7 @@ Texture* DXRenderDevice::CreateRenderTarget(int width, int height, bool destAlph
aRenderTarget->mWidth = width;
aRenderTarget->mHeight = height;
aRenderTarget->mRenderDevice = this;
aRenderTarget->mD3DTexture = d3DTexture;
aRenderTarget->mD3DResourceView = d3DShaderResourceView;
aRenderTarget->mD3DRenderTargetView = d3DRenderTargetView;
aRenderTarget->AddRef();

View file

@ -44,6 +44,7 @@
#include "gfx/DrawLayer.h"
#include "gfx/ModelInstance.h"
#include "util/HashSet.h"
#include "util/Dictionary.h"
#include <map>
NS_BF_BEGIN;
@ -55,6 +56,7 @@ class DXRenderDevice;
class DXTexture : public Texture
{
public:
String mPath;
DXRenderDevice* mRenderDevice;
ID3D11Texture2D* mD3DTexture;
ID3D11ShaderResourceView* mD3DResourceView;
@ -124,8 +126,8 @@ class DXDrawLayer : public DrawLayer
public:
virtual DrawBatch* CreateDrawBatch();
virtual RenderCmd* CreateSetTextureCmd(int textureIdx, Texture* texture) override;
virtual void SetShaderConstantData(int slotIdx, void* constData, int size) override;
virtual void SetShaderConstantDataTyped(int slotIdx, void* constData, int size, int* typeData, int typeCount) override;
virtual void SetShaderConstantData(int usageIdx, int slotIdx, void* constData, int size) override;
virtual void SetShaderConstantDataTyped(int usageIdx, int slotIdx, void* constData, int size, int* typeData, int typeCount) override;
public:
DXDrawLayer();
@ -203,32 +205,40 @@ public:
void IndalidateDepthStencilState();
virtual void SetClipped(bool clipped);
virtual void SetTexWrap(bool clipped);
virtual void SetClipRect(const Rect& rect);
virtual void SetWriteDepthBuffer(bool writeDepthBuffer);
virtual void SetDepthFunc(DepthFunc depthFunc);
};
class DXModelMesh
class DXModelPrimitives
{
public:
String mMaterialName;
int mNumIndices;
int mNumVertices;
DXTexture* mTexture;
Array<DXTexture*> mTextures;
ID3D11Buffer* mD3DIndexBuffer;
//TODO: Split the vertex buffer up into static and dynamic buffers
ID3D11Buffer* mD3DVertexBuffer;
public:
DXModelMesh();
~DXModelMesh();
DXModelPrimitives();
~DXModelPrimitives();
};
class DXModelMesh
{
public:
Array<DXModelPrimitives> mPrimitives;
};
class DXModelInstance : public ModelInstance
{
public:
DXRenderDevice* mD3DRenderDevice;
std::vector<DXModelMesh> mDXModelMeshs;
Array<DXModelMesh> mDXModelMeshs;
public:
DXModelInstance(ModelDef* modelDef);
@ -274,6 +284,7 @@ public:
ID3D11DeviceContext* mD3DDeviceContext;
ID3D11BlendState* mD3DNormalBlendState;
ID3D11SamplerState* mD3DDefaultSamplerState;
ID3D11SamplerState* mD3DWrapSamplerState;
bool mHasVSync;
ID3D11Buffer* mD3DVertexBuffer;
@ -283,6 +294,8 @@ public:
HashSet<DXRenderState*> mRenderStates;
HashSet<DXTexture*> mTextures;
Dictionary<String, DXTexture*> mTextureMap;
Dictionary<int, ID3D11Buffer*> mBufferMap;
public:
virtual void PhysSetRenderState(RenderState* renderState) override;
@ -302,6 +315,7 @@ public:
void FrameStart() override;
void FrameEnd() override;
Texture* LoadTexture(const StringImpl& fileName, int flags) override;
Texture* LoadTexture(ImageData* imageData, int flags) override;
Texture* CreateDynTexture(int width, int height) override;
Shader* LoadShader(const StringImpl& fileName, VertexDefinition* vertexDefinition) override;

View file

@ -2637,6 +2637,9 @@ BFP_EXPORT void BFP_CALLTYPE BfpDirectory_GetSysDirectory(BfpSysDirectoryKind sy
case BfpSysDirectoryKind_Programs_Common:
_GetKnownFolder(FOLDERID_CommonPrograms);
return;
case BfpSysDirectoryKind_Documents:
_GetKnownFolder(FOLDERID_Documents);
return;
}
TryStringOut(path, outPath, inOutPathLen, (BfpResult*)outResult);

View file

@ -26,11 +26,11 @@ Beefy::Quaternion Beefy::Quaternion::Slerp(float fT, const Quaternion& rkP, cons
if ((fabs(fCos) < 1.0f - BF_MS_EPSILON) && (false))
{
// Standard case (slerp)
float fSin = sqrt(1.0f - (fCos * fCos));
float fAngle = atan2(fSin, fCos);
float fSin = sqrtf(1.0f - (fCos * fCos));
float fAngle = atan2f(fSin, fCos);
float fInvSin = 1.0f / fSin;
float fCoeff0 = sin((1.0f - fT) * fAngle) * fInvSin;
float fCoeff1 = sin(fT * fAngle) * fInvSin;
float fCoeff0 = sinf((1.0f - fT) * fAngle) * fInvSin;
float fCoeff1 = sinf(fT * fAngle) * fInvSin;
return fCoeff0 * rkP + fCoeff1 * rkT;
}
else

View file

@ -114,7 +114,7 @@ public:
static Quaternion Normalise(const Quaternion& quat)
{
float len = quat.Norm();
float factor = 1.0f / sqrt(len);
float factor = 1.0f / sqrtf(len);
return quat * factor;
}
};

View file

@ -13,7 +13,7 @@ Vector3::Vector3(float x, float y, float z)
float Vector3::GetMagnitude() const
{
return sqrt(mX*mX + mY*mY + mZ*mZ);
return sqrtf(mX*mX + mY*mY + mZ*mZ);
}
Vector3 Vector3::Normalize(const Vector3& vec)
@ -76,3 +76,13 @@ Vector3 Vector3::Transform2(const Vector3& vec, const Quaternion& quat)
return result;
}
///
Vector4::Vector4(float x, float y, float z, float w)
{
mX = x;
mY = y;
mZ = z;
mW = w;
}

View file

@ -94,4 +94,64 @@ public:
}
};
class Vector4
{
public:
float mX;
float mY;
float mZ;
float mW;
public:
Vector4(float x = 0, float y = 0, float z = 0, float w = 0);
bool operator==(const Vector4& check) const
{
return (mX == check.mX) && (mY == check.mY) && (mZ == check.mZ);
}
bool operator!=(const Vector4& check) const
{
return (mX != check.mX) || (mY != check.mY) || (mZ != check.mZ);
}
static Vector4 Scale(const Vector4& vec, float scale)
{
return Vector4(vec.mX * scale, vec.mY * scale, vec.mZ * scale, vec.mW * scale);
}
Vector4 operator +(const Vector4& v2) const
{
return Vector4(mX + v2.mX, mY + v2.mY, mZ + v2.mZ, mW + v2.mW);
}
Vector4 operator *(const Vector4& v2) const
{
return Vector4(mX * v2.mX, mY * v2.mY, mZ * v2.mZ, mW * v2.mW);
}
Vector4 operator *(float scale) const
{
return Vector4(mX * scale, mY * scale, mZ * scale, mW * scale);
}
inline Vector4& operator -= (const Vector4& vec)
{
mX -= vec.mX;
mY -= vec.mY;
mZ -= vec.mZ;
mW -= vec.mW;
return *this;
}
inline Vector4& operator *= (const Vector4& vec)
{
mX *= vec.mX;
mY *= vec.mY;
mZ *= vec.mZ;
mW *= vec.mW;
return *this;
}
};
NS_BF_END;