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

Additional 3d support

This commit is contained in:
Brian Fiete 2021-05-25 10:57:22 -04:00
parent 369bb0640c
commit 39c140f44a
27 changed files with 4063 additions and 126 deletions

View file

@ -610,6 +610,23 @@ BF_EXPORT void BF_CALLTYPE Gfx_DrawQuads(TextureSegment* textureSegment, Default
}
}
BF_EXPORT void BF_CALLTYPE Gfx_DrawIndexedVertices(int vertexSize, void* vtxData, int vtxCount, uint16* idxData, int idxCount)
{
DrawLayer* drawLayer = gBFApp->mRenderDevice->mCurDrawLayer;
uint16 idxOfs;
void* drawBatchVtxPtr;
uint16* drawBatchIdxPtr;
gBFApp->mRenderDevice->mCurDrawLayer->AllocIndexed(vtxCount, idxCount, (void**)&drawBatchVtxPtr, &drawBatchIdxPtr, &idxOfs);
BF_ASSERT(gBFApp->mRenderDevice->mCurDrawLayer->mCurDrawBatch->mVtxSize == vertexSize);
uint16* idxPtr = idxData;
for (int idxIdx = 0; idxIdx < idxCount; idxIdx++)
*(drawBatchIdxPtr++) = *(idxPtr++) + idxOfs;
memcpy(drawBatchVtxPtr, vtxData, vertexSize * vtxCount);
}
BF_EXPORT void BF_CALLTYPE Gfx_DrawIndexedVertices2D(int vertexSize, void* vtxData, int vtxCount, uint16* idxData, int idxCount, float a, float b, float c, float d, float tx, float ty, float z)
{
DrawLayer* drawLayer = gBFApp->mRenderDevice->mCurDrawLayer;
@ -683,6 +700,11 @@ BF_EXPORT void BF_CALLTYPE RenderState_SetTexWrap(RenderState* renderState, bool
renderState->SetTexWrap(texWrap);
}
BF_EXPORT void BF_CALLTYPE RenderState_SetWireframe(RenderState* renderState, bool wireframe)
{
renderState->SetWireframe(wireframe);
}
BF_EXPORT void BF_CALLTYPE RenderState_SetClip(RenderState* renderState, float x, float y, float width, float height)
{
BF_ASSERT((width >= 0) && (height >= 0));
@ -720,6 +742,11 @@ BF_EXPORT void BF_CALLTYPE RenderState_SetDepthWrite(RenderState* renderState, i
renderState->SetWriteDepthBuffer(depthWrite != 0);
}
BF_EXPORT void BF_CALLTYPE RenderState_SetTopology(RenderState* renderState, int topology)
{
renderState->SetTopology((Topology3D)topology);
}
BF_EXPORT Shader* BF_CALLTYPE Gfx_LoadShader(const char* fileName, VertexDefinition* vertexDefinition)
{
return gBFApp->mRenderDevice->LoadShader(fileName, vertexDefinition);

View file

@ -1936,11 +1936,13 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClCompile Include="util\Heap.cpp" />
<ClCompile Include="util\Json.cpp" />
<ClCompile Include="util\MappedFile.cpp" />
<ClCompile Include="util\MathUtils.cpp" />
<ClCompile Include="util\Matrix4.cpp" />
<ClCompile Include="util\PerfTimer.cpp" />
<ClCompile Include="util\Point.cpp" />
<ClCompile Include="util\PolySpline.cpp" />
<ClCompile Include="util\Quaternion.cpp" />
<ClCompile Include="util\Sphere.cpp" />
<ClCompile Include="util\StackHelper.cpp" />
<ClCompile Include="util\String.cpp" />
<ClCompile Include="util\ThreadPool.cpp" />
@ -2166,6 +2168,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClInclude Include="util\Heap.h" />
<ClInclude Include="util\Json.h" />
<ClInclude Include="util\MappedFile.h" />
<ClInclude Include="util\MathUtils.h" />
<ClInclude Include="util\Matrix4.h" />
<ClInclude Include="util\MultiHashSet.h" />
<ClInclude Include="util\PerfTimer.h" />
@ -2176,6 +2179,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClInclude Include="util\Rect.h" />
<ClInclude Include="util\SizedArray.h" />
<ClInclude Include="util\SLIList.h" />
<ClInclude Include="util\Sphere.h" />
<ClInclude Include="util\StackHelper.h" />
<ClInclude Include="util\String.h" />
<ClInclude Include="util\ThreadPool.h" />

View file

@ -713,6 +713,12 @@
<ClCompile Include="util\Json.cpp">
<Filter>src\util</Filter>
</ClCompile>
<ClCompile Include="util\MathUtils.cpp">
<Filter>src\util</Filter>
</ClCompile>
<ClCompile Include="util\Sphere.cpp">
<Filter>src\util</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Common.h">
@ -1087,6 +1093,12 @@
<ClInclude Include="util\Json.h">
<Filter>src\util</Filter>
</ClInclude>
<ClInclude Include="util\MathUtils.h">
<Filter>src\util</Filter>
</ClInclude>
<ClInclude Include="util\Sphere.h">
<Filter>src\util</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">

View file

@ -6,6 +6,10 @@
#include "util/TLSingleton.h"
#include "FileStream.h"
#include "MemStream.h"
#include "util/MathUtils.h"
#include "util/Sphere.h"
#include "util/HashSet.h"
#include "util/BeefPerf.h"
#pragma warning(disable:4190)
@ -50,14 +54,30 @@ void Beefy::ModelAnimation::GetJointTranslation(int jointIdx, float frameNum, Mo
//
BF_EXPORT ModelInstance* BF_CALLTYPE ModelDef_CreateModelInstance(ModelDef* modelDef)
BF_EXPORT ModelInstance* BF_CALLTYPE ModelDef_CreateModelInstance(ModelDef* modelDef, ModelCreateFlags flags)
{
return gBFApp->mRenderDevice->CreateModelInstance(modelDef);
return gBFApp->mRenderDevice->CreateModelInstance(modelDef, flags);
}
BF_EXPORT void ModelDef_Compact(ModelDef* modelDef)
{
modelDef->Compact();
}
BF_EXPORT void ModelDef_GetBounds(ModelDef* modelDef, Vector3& min, Vector3& max)
{
modelDef->GetBounds(min, max);
}
BF_EXPORT void ModelDef_SetBaseDir(ModelDef* modelDef, char* baseDIr)
{
modelDef->mLoadDir = baseDIr;
}
BF_EXPORT const char* BF_CALLTYPE ModelDef_GetInfo(ModelDef* modelDef)
{
String& outString = *gModelDef_TLStrReturn.Get();
outString.Clear();
for (int meshIdx = 0; meshIdx < (int)modelDef->mMeshes.mSize; meshIdx++)
{
auto mesh = modelDef->mMeshes[meshIdx];
@ -105,6 +125,11 @@ BF_EXPORT void BF_CALLTYPE ModelDef_SetTextures(ModelDef* modelDef, int32 meshId
prims.mTexPaths.Add(paths[i]);
}
BF_EXPORT bool BF_CALLTYPE ModelDef_RayIntersect(ModelDef* modelDef, const Matrix4& worldMtx, const Vector3& origin, const Vector3& vec, Vector3& outIntersect, float& outDistance)
{
return modelDef->RayIntersect(worldMtx, origin, vec, outIntersect, outDistance);
}
BF_EXPORT void BF_CALLTYPE ModelDefAnimation_GetJointTranslation(ModelAnimation* modelAnimation, int jointIdx, float frame, ModelJointTranslation* outJointTranslation)
{
modelAnimation->GetJointTranslation(jointIdx, frame, outJointTranslation);
@ -126,6 +151,11 @@ BF_EXPORT void BF_CALLTYPE ModelDefAnimation_Clip(ModelAnimation* modelAnimation
modelAnimation->mFrames.RemoveRange(numFrames, modelAnimation->mFrames.Count() - numFrames);
}
ModelDef::ModelDef()
{
mFlags = Flags_None;
}
ModelDef::~ModelDef()
{
for (auto& materialInstance : mMaterials)
@ -134,6 +164,459 @@ ModelDef::~ModelDef()
}
}
void ModelDef::Compact()
{
for (auto& mesh : mMeshes)
{
for (auto& prims : mesh.mPrimitives)
{
Array<int> vtxMap;
vtxMap.Insert(0, -1, prims.mVertices.mSize);
int newVtxIdx = 0;
for (uint16 vtxIdx : prims.mIndices)
{
if (vtxMap[vtxIdx] == -1)
vtxMap[vtxIdx] = newVtxIdx++;
}
if (newVtxIdx >= prims.mVertices.mSize)
continue;
for (uint16& vtxIdx : prims.mIndices)
vtxIdx = vtxMap[vtxIdx];
Array<ModelVertex> oldVertices = prims.mVertices;
prims.mVertices.Resize(newVtxIdx);
for (int oldVtxIdx = 0; oldVtxIdx < oldVertices.mSize; oldVtxIdx++)
{
int newVtxIdx = vtxMap[oldVtxIdx];
if (newVtxIdx != -1)
prims.mVertices[newVtxIdx] = oldVertices[oldVtxIdx];
}
}
}
}
void ModelDef::CalcBounds()
{
int vtxCount = 0;
for (auto& mesh : mMeshes)
{
for (auto& prims : mesh.mPrimitives)
{
for (auto& vtx : prims.mVertices)
{
if (vtxCount == 0)
{
mBounds.mMin = vtx.mPosition;
mBounds.mMax = vtx.mPosition;
}
else
{
mBounds.mMin.mX = BF_MIN(mBounds.mMin.mX, vtx.mPosition.mX);
mBounds.mMin.mY = BF_MIN(mBounds.mMin.mY, vtx.mPosition.mY);
mBounds.mMin.mZ = BF_MIN(mBounds.mMin.mZ, vtx.mPosition.mZ);
mBounds.mMax.mX = BF_MAX(mBounds.mMax.mX, vtx.mPosition.mX);
mBounds.mMax.mY = BF_MAX(mBounds.mMax.mY, vtx.mPosition.mY);
mBounds.mMax.mZ = BF_MAX(mBounds.mMax.mZ, vtx.mPosition.mZ);
}
vtxCount++;
}
}
}
mFlags = (Flags)(mFlags | Flags_HasBounds);
}
void ModelDef::GetBounds(Vector3& min, Vector3& max)
{
if ((mFlags & Flags_HasBounds) == 0)
CalcBounds();
min = mBounds.mMin;
max = mBounds.mMax;
}
#define SWAP(x, y) { auto temp = x; x = y; y = temp; }
#define N (sizeof(A)/sizeof(A[0]))
// Partition using Lomuto partition scheme
static int partition(float a[], int left, int right, int pIndex)
{
// pick `pIndex` as a pivot from the array
float pivot = a[pIndex];
// Move pivot to end
SWAP(a[pIndex], a[right]);
// elements less than the pivot will be pushed to the left of `pIndex`;
// elements more than the pivot will be pushed to the right of `pIndex`;
// equal elements can go either way
pIndex = left;
// each time we find an element less than or equal to the pivot, `pIndex`
// is incremented, and that element would be placed before the pivot.
for (int i = left; i < right; i++)
{
if (a[i] <= pivot)
{
SWAP(a[i], a[pIndex]);
pIndex++;
}
}
// move pivot to its final place
SWAP(a[pIndex], a[right]);
// return `pIndex` (index of the pivot element)
return pIndex;
}
// Returns the k'th smallest element in the list within `left…right`
// (i.e., `left <= k <= right`). The search space within the array is
// changing for each round but the list is still the same size.
// Thus, `k` does not need to be updated with each round.
static float quickselect(float A[], int left, int right, int k)
{
// If the array contains only one element, return that element
if (left == right) {
return A[left];
}
// select `pIndex` between left and right
int pIndex = left + rand() % (right - left + 1);
pIndex = partition(A, left, right, pIndex);
// The pivot is in its final sorted position
if (k == pIndex) {
return A[k];
}
// if `k` is less than the pivot index
else if (k < pIndex) {
return quickselect(A, left, pIndex - 1, k);
}
// if `k` is more than the pivot index
else {
return quickselect(A, pIndex + 1, right, k);
}
}
void ModelDef::GenerateCollisionData()
{
BP_ZONE("ModelDef::GenerateCollisionData");
mFlags = (Flags)(mFlags | Flags_HasBVH);
int statsWorkItrs = 0;
int statsWorkTris = 0;
BF_ASSERT(mBVNodes.IsEmpty());
struct _WorkEntry
{
int mParentNodeIdx;
int mTriWorkIdx;
int mTriWorkCount;
};
Array<int32> triWorkList;
int triCount = 0;
for (auto& mesh : mMeshes)
{
for (auto& prims : mesh.mPrimitives)
{
int startIdx = mBVIndices.mSize;
triCount += prims.mIndices.mSize / 3;
triWorkList.Reserve(triWorkList.mSize + triCount);
mBVIndices.Reserve(mBVIndices.mSize + prims.mIndices.mSize);
mBVVertices.Reserve(mBVVertices.mSize + prims.mVertices.mSize);
for (int triIdx = 0; triIdx < triCount; triIdx++)
triWorkList.Add(startIdx / 3 + triIdx);
for (auto idx : prims.mIndices)
{
mBVIndices.Add(idx + startIdx);
}
for (auto& vtx : prims.mVertices)
mBVVertices.Add(vtx.mPosition);
}
}
Array<_WorkEntry> workList;
_WorkEntry workEntry;
workEntry.mParentNodeIdx = -1;
workEntry.mTriWorkIdx = 0;
workEntry.mTriWorkCount = triWorkList.mSize;
workList.Add(workEntry);
Array<Vector3> points;
points.Reserve(triWorkList.mSize);
Array<float> centers;
centers.Reserve(triWorkList.mSize);
Array<int> left;
left.Reserve(triWorkList.mSize);
Array<int> right;
right.Reserve(triWorkList.mSize);
mBVTris.Reserve(triWorkList.mSize * 2);
while (!workList.IsEmpty())
{
auto workEntry = workList.back();
workList.pop_back();
statsWorkItrs++;
statsWorkTris += workEntry.mTriWorkCount;
centers.Clear();
left.Clear();
right.Clear();
int nodeIdx = mBVNodes.mSize;
mBVNodes.Add(ModelBVNode());
if (workEntry.mParentNodeIdx != -1)
{
auto& bvParent = mBVNodes[workEntry.mParentNodeIdx];
if (bvParent.mLeft == -1)
bvParent.mLeft = nodeIdx;
else
{
BF_ASSERT(bvParent.mRight == -1);
bvParent.mRight = nodeIdx;
}
}
for (int triIdxIdx = 0; triIdxIdx < workEntry.mTriWorkCount; triIdxIdx++)
{
bool inLeft = false;
bool inRight = false;
int triIdx = triWorkList.mVals[workEntry.mTriWorkIdx + triIdxIdx];
for (int triVtxIdx = 0; triVtxIdx < 3; triVtxIdx++)
{
int vtxIdx = mBVIndices.mVals[triIdx * 3 + triVtxIdx];
bool isNewVtx = false;
int32* valuePtr = NULL;
auto& vtx = mBVVertices[vtxIdx];
auto& bvNode = mBVNodes[nodeIdx];
if ((triIdxIdx == 0) && (triVtxIdx == 0))
{
bvNode.mBoundAABB.mMin = vtx;
bvNode.mBoundAABB.mMax = vtx;
}
else
{
bvNode.mBoundAABB.mMin.mX = BF_MIN(bvNode.mBoundAABB.mMin.mX, vtx.mX);
bvNode.mBoundAABB.mMin.mY = BF_MIN(bvNode.mBoundAABB.mMin.mY, vtx.mY);
bvNode.mBoundAABB.mMin.mZ = BF_MIN(bvNode.mBoundAABB.mMin.mZ, vtx.mZ);
bvNode.mBoundAABB.mMax.mX = BF_MAX(bvNode.mBoundAABB.mMax.mX, vtx.mX);
bvNode.mBoundAABB.mMax.mY = BF_MAX(bvNode.mBoundAABB.mMax.mY, vtx.mY);
bvNode.mBoundAABB.mMax.mZ = BF_MAX(bvNode.mBoundAABB.mMax.mZ, vtx.mZ);
}
}
}
//mBVNodes[nodeIdx].mBoundSphere = Sphere::MiniBall(points.mVals, points.mSize);
bool didSplit = false;
if (workEntry.mTriWorkCount > 4)
{
int splitPlane = 0;
float splitWidth = 0;
// Split along widest AABB dimension
for (int dimIdx = 0; dimIdx < 3; dimIdx++)
{
float minVal = 0;
float maxVal = 0;
for (int triIdxIdx = 0; triIdxIdx < workEntry.mTriWorkCount; triIdxIdx++)
{
int triIdx = triWorkList.mVals[workEntry.mTriWorkIdx + triIdxIdx];
for (int triVtxIdx = 0; triVtxIdx < 3; triVtxIdx++)
{
int vtxIdx = mBVIndices.mVals[triIdx * 3 + triVtxIdx];
const Vector3& vtx = mBVVertices.mVals[vtxIdx];
float coord = ((float*)&vtx)[dimIdx];
if ((triIdxIdx == 0) && (triVtxIdx == 0))
{
minVal = coord;
maxVal = coord;
}
else
{
minVal = BF_MIN(minVal, coord);
maxVal = BF_MAX(maxVal, coord);
}
}
}
float width = maxVal - minVal;
if (width > splitWidth)
{
splitPlane = dimIdx;
splitWidth = width;
}
}
centers.SetSize(workEntry.mTriWorkCount);
for (int triIdxIdx = 0; triIdxIdx < workEntry.mTriWorkCount; triIdxIdx++)
{
int triIdx = triWorkList.mVals[workEntry.mTriWorkIdx + triIdxIdx];
float coordAcc = 0;
for (int triVtxIdx = 0; triVtxIdx < 3; triVtxIdx++)
{
int vtxIdx = mBVIndices.mVals[triIdx * 3 + triVtxIdx];
const Vector3& vtx = mBVVertices.mVals[vtxIdx];
float coord = ((float*)&vtx)[splitPlane];
coordAcc += coord;
}
float coordAvg = coordAcc / 3;
centers.mVals[triIdxIdx] = coordAvg;
}
float centerCoord = quickselect(centers.mVals, 0, centers.mSize - 1, centers.mSize / 2);
// centers.Sort([](float lhs, float rhs) { return lhs < rhs; });
// centerCoord = centers[centers.mSize / 2];
for (int triIdxIdx = 0; triIdxIdx < workEntry.mTriWorkCount; triIdxIdx++)
{
bool inLeft = false;
bool inRight = false;
int triIdx = triWorkList.mVals[workEntry.mTriWorkIdx + triIdxIdx];
for (int triVtxIdx = 0; triVtxIdx < 3; triVtxIdx++)
{
int vtxIdx = mBVIndices.mVals[triIdx * 3 + triVtxIdx];
const Vector3& vtx = mBVVertices.mVals[vtxIdx];
float coord = ((float*)&vtx)[splitPlane];
if (coord < centerCoord)
inLeft = true;
else
inRight = true;
}
if (inLeft)
left.Add(triIdx);
if (inRight)
right.Add(triIdx);
}
// Don't split if the split didn't significantly separate the triangles
bool doSplit =
(left.mSize <= workEntry.mTriWorkCount * 0.85f) &&
(right.mSize <= workEntry.mTriWorkCount * 0.85f);
if (doSplit)
{
mBVNodes[nodeIdx].mKind = ModelBVNode::Kind_Branch;
mBVNodes[nodeIdx].mLeft = -1;
mBVNodes[nodeIdx].mRight = -1;
_WorkEntry childWorkEntry;
childWorkEntry.mParentNodeIdx = nodeIdx;
childWorkEntry.mTriWorkIdx = triWorkList.mSize;
childWorkEntry.mTriWorkCount = right.mSize;
workList.Add(childWorkEntry);
triWorkList.Insert(triWorkList.mSize, right.mVals, right.mSize);
childWorkEntry.mParentNodeIdx = nodeIdx;
childWorkEntry.mTriWorkIdx = triWorkList.mSize;
childWorkEntry.mTriWorkCount = left.mSize;
workList.Add(childWorkEntry);
triWorkList.Insert(triWorkList.mSize, left.mVals, left.mSize);
continue;
}
}
// Did not split
int triStartIdx = mBVTris.mSize;
//mBVTris.Reserve(mBVTris.mSize + workEntry.mTriWorkCount);
for (int triIdxIdx = 0; triIdxIdx < workEntry.mTriWorkCount; triIdxIdx++)
mBVTris.Add(triWorkList[workEntry.mTriWorkIdx + triIdxIdx]);
auto& bvNode = mBVNodes[nodeIdx];
bvNode.mKind = ModelBVNode::Kind_Leaf;
bvNode.mTriStartIdx = triStartIdx;
bvNode.mTriCount = workEntry.mTriWorkCount;
}
NOP;
}
void ModelDef::RayIntersect(ModelBVNode* bvNode, const Matrix4& worldMtx, const Vector3& origin, const Vector3& vec, Vector3& outIntersect, float& outDistance)
{
// if (!RayIntersectsCircle(origin, vec, bvNode->mBoundSphere, NULL, NULL, NULL))
// return false;
if (!RayIntersectsAABB(origin, vec, bvNode->mBoundAABB, NULL, NULL, NULL))
return;
if (bvNode->mKind == ModelBVNode::Kind_Branch)
{
bool hadIntersect = false;
for (int branchIdx = 0; branchIdx < 2; branchIdx++)
RayIntersect(&mBVNodes[(branchIdx == 0) ? bvNode->mLeft : bvNode->mRight], worldMtx, origin, vec, outIntersect, outDistance);
return;
}
for (int triIdxIdx = 0; triIdxIdx < bvNode->mTriCount; triIdxIdx++)
{
int triIdx = mBVTris[bvNode->mTriStartIdx + triIdxIdx];
Vector3 curIntersect;
float curDistance;
if (RayIntersectsTriangle(origin, vec,
mBVVertices[mBVIndices[triIdx*3+0]], mBVVertices[mBVIndices[triIdx*3+1]], mBVVertices[mBVIndices[triIdx*3+2]],
&curIntersect, &curDistance))
{
if (curDistance < outDistance)
{
outIntersect = curIntersect;
outDistance = curDistance;
}
}
}
}
bool ModelDef::RayIntersect(const Matrix4& worldMtx, const Vector3& origin, const Vector3& vec, Vector3& outIntersect, float& outDistance)
{
if ((mFlags & Flags_HasBounds) == 0)
CalcBounds();
if (!RayIntersectsAABB(origin, vec, mBounds, NULL, NULL, NULL))
return false;
if (mBVNodes.IsEmpty())
GenerateCollisionData();
const float maxDist = 3.40282e+038f;
outDistance = maxDist;
RayIntersect(&mBVNodes[0], worldMtx, origin, vec, outIntersect, outDistance);
return outDistance != maxDist;
}
ModelMaterialDef* ModelMaterialDef::CreateOrGet(const StringImpl& prefix, const StringImpl& path)
{
StringT<128> key = prefix;
@ -211,7 +694,7 @@ public:
bool ReadFile(const StringImpl& fileName, const StringImpl& baseDir)
{
if (fileName.Contains(':'))
if (fileName.StartsWith('@'))
{
int colon = (int)fileName.IndexOf(':');
String addrStr = fileName.Substring(1, colon - 1);
@ -286,5 +769,7 @@ BF_EXPORT StringView BF_CALLTYPE Res_SerializeModel(ModelDef* modelDef)
}
String& outString = *gModelDef_TLStrReturn.Get();
outString.Clear();
outString.Append((char*)ms.GetPtr(), ms.GetSize());
return outString;
}

View file

@ -5,6 +5,8 @@
#include "util/Vector.h"
#include "util/Array.h"
#include "gfx/Texture.h"
#include "util/Sphere.h"
#include "util/MathUtils.h"
#include <vector>
NS_BF_BEGIN;
@ -151,8 +153,6 @@ class ModelMesh
{
public:
String mName;
//String mTexFileName;
//String mBumpFileName;
Array<ModelPrimitives> mPrimitives;
};
@ -166,19 +166,83 @@ public:
Array<ModelNode*> mChildren;
};
class ModelBVNode
{
public:
enum Kind
{
Kind_None,
Kind_Branch,
Kind_Leaf
};
public:
Sphere mBoundSphere;
AABB mBoundAABB;
union
{
struct
{
int mLeft;
int mRight;
};
struct
{
int mTriStartIdx;
int mTriCount;
};
};
Kind mKind;
public:
ModelBVNode()
{
mKind = Kind_None;
}
};
class ModelDef
{
public:
enum Flags
{
Flags_None,
Flags_HasBounds,
Flags_HasBVH,
};
public:
String mLoadDir;
float mFrameRate;
float mFrameRate;
Array<ModelMesh> mMeshes;
Array<ModelJoint> mJoints;
Array<ModelAnimation> mAnims;
Array<ModelNode> mNodes;
Array<ModelMaterialInstance> mMaterials;
Flags mFlags;
AABB mBounds;
Array<ModelBVNode> mBVNodes;
Array<uint16> mBVIndices;
Array<Vector3> mBVVertices;
Array<int32> mBVTris;
protected:
void CalcBounds();
void RayIntersect(ModelBVNode* bvNode, const Matrix4& worldMtx, const Vector3& origin, const Vector3& vec, Vector3& outIntersect, float& outDistance);
public:
ModelDef();
~ModelDef();
void Compact();
void GetBounds(Vector3& min, Vector3& max);
void GenerateCollisionData();
bool RayIntersect(const Matrix4& worldMtx, const Vector3& origin, const Vector3& vec, Vector3& outIntersect, float& outDistance);
};
NS_BF_END;

View file

@ -19,9 +19,11 @@ RenderState::RenderState()
mWriteDepthBuffer = false;
mCullMode = CullMode_None;
mDepthFunc = DepthFunc_Always;
mTopology = Topology3D_TriangleList;
mShader = NULL;
mClipped = false;
mTexWrap = false;
mWireframe = false;
}
RenderTarget::RenderTarget()

View file

@ -143,6 +143,12 @@ enum CullMode : int8
CullMode_Back
};
enum Topology3D : int8
{
Topology3D_TriangleList,
Topology3D_LineLine
};
enum TextureFlag : int8
{
TextureFlag_Additive = 1,
@ -183,8 +189,10 @@ public:
DepthFunc mDepthFunc;
bool mClipped;
bool mTexWrap;
bool mWireframe;
Rect mClipRect;
CullMode mCullMode;
Topology3D mTopology;
public:
RenderState();
@ -192,10 +200,12 @@ public:
virtual void SetShader(Shader* shader) { mShader = shader; }
virtual void SetTexWrap(bool wrap) { mTexWrap = wrap; }
virtual void SetWireframe(bool wireframe) { mWireframe = wireframe; }
virtual void SetClipped(bool clipped) { mClipped = clipped; }
virtual void SetClipRect(const Rect& rect) { mClipRect = rect; }
virtual void SetWriteDepthBuffer(bool writeDepthBuffer) { mWriteDepthBuffer = writeDepthBuffer; }
virtual void SetDepthFunc(DepthFunc depthFunc) { mDepthFunc = depthFunc; }
virtual void SetTopology(Topology3D topology) { mTopology = topology; }
};
class PoolData
@ -241,6 +251,12 @@ public:
}
};
enum ModelCreateFlags
{
ModelCreateFlags_None = 0,
ModelCreateFlags_NoSetRenderState = 1
};
class RenderDevice
{
public:
@ -272,7 +288,7 @@ public:
virtual void RemoveRenderWindow(RenderWindow* renderWindow);
virtual RenderState* CreateRenderState(RenderState* srcRenderState);
virtual ModelInstance* CreateModelInstance(ModelDef* modelDef) { return NULL; }
virtual ModelInstance* CreateModelInstance(ModelDef* modelDef, ModelCreateFlags flags) { return NULL; }
virtual VertexDefinition* CreateVertexDefinition(VertexDefData* elementData, int numElements);
virtual void FrameStart() = 0;

View file

@ -143,9 +143,9 @@ static int GetBytesPerPixel(DXGI_FORMAT fmt, int& blockSize)
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_BC7_TYPELESS: blockSize = 4; return 16;
case DXGI_FORMAT_BC7_UNORM: blockSize = 4; return 16;
case DXGI_FORMAT_BC7_UNORM_SRGB: blockSize = 4; return 16;
case DXGI_FORMAT_AYUV: return 1;
case DXGI_FORMAT_Y410: return 1;
case DXGI_FORMAT_Y416: return 1;
@ -510,9 +510,17 @@ void DXRenderDevice::PhysSetRenderState(RenderState* renderState)
DXRenderState* dxRenderState = (DXRenderState*)renderState;
DXShader* dxShader = (DXShader*)renderState->mShader;
if ((renderState->mShader != mPhysRenderState->mShader) && (renderState->mShader != NULL))
if (renderState->mTopology != mPhysRenderState->mTopology)
{
mD3DDeviceContext->PSSetSamplers(0, 1, mPhysRenderState->mTexWrap ? &mD3DWrapSamplerState : &mD3DDefaultSamplerState);
D3D_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
if (dxRenderState->mTopology == Topology3D_LineLine)
topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
mD3DDeviceContext->IASetPrimitiveTopology(topology);
}
if ((renderState->mShader != mPhysRenderState->mShader) && (renderState->mShader != NULL))
{
mD3DDeviceContext->PSSetSamplers(0, 1, renderState->mTexWrap ? &mD3DWrapSamplerState : &mD3DDefaultSamplerState);
mD3DDeviceContext->IASetInputLayout(dxShader->mD3DLayout);
mD3DDeviceContext->VSSetShader(dxShader->mD3DVertexShader, NULL, 0);
mD3DDeviceContext->PSSetShader(dxShader->mD3DPixelShader, NULL, 0);
@ -591,6 +599,9 @@ void DXRenderDevice::PhysSetRenderState(RenderState* renderState)
setRasterizerState = true;
}
if (renderState->mWireframe != mPhysRenderState->mWireframe)
setRasterizerState = true;
if (setRasterizerState)
{
if (dxRenderState->mD3DRasterizerState == NULL)
@ -599,13 +610,13 @@ void DXRenderDevice::PhysSetRenderState(RenderState* renderState)
{
D3D11_CULL_NONE,
D3D11_CULL_FRONT,
D3D11_CULL_BACK
D3D11_CULL_BACK
};
D3D11_RASTERIZER_DESC rasterizerState;
rasterizerState.CullMode = cullModes[dxRenderState->mCullMode];
//rasterizerState.CullMode = D3D11_CULL_BACK;
rasterizerState.FillMode = D3D11_FILL_SOLID;
rasterizerState.FillMode = renderState->mWireframe ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID;
rasterizerState.FrontCounterClockwise = false;
rasterizerState.DepthBias = 0;
rasterizerState.DepthBiasClamp = 0;
@ -701,7 +712,7 @@ struct DXModelVertex
Vector3 mTangent;
};
ModelInstance* DXRenderDevice::CreateModelInstance(ModelDef* modelDef)
ModelInstance* DXRenderDevice::CreateModelInstance(ModelDef* modelDef, ModelCreateFlags flags)
{
DXModelInstance* dxModelInstance = new DXModelInstance(modelDef);
@ -718,16 +729,17 @@ ModelInstance* DXRenderDevice::CreateModelInstance(ModelDef* modelDef)
};
auto vertexDefinition = CreateVertexDefinition(vertexDefData, sizeof(vertexDefData) / sizeof(vertexDefData[0]));
auto renderState = CreateRenderState(mDefaultRenderState);
renderState->mShader = LoadShader(gBFApp->mInstallDir + "/shaders/ModelStd", vertexDefinition);
RenderState* renderState = NULL;
if ((flags & ModelCreateFlags_NoSetRenderState) == 0)
{
renderState = CreateRenderState(mDefaultRenderState);
renderState->mShader = LoadShader(gBFApp->mInstallDir + "/shaders/ModelStd", vertexDefinition);
renderState->mTexWrap = true;
renderState->mDepthFunc = DepthFunc_LessEqual;
renderState->mWriteDepthBuffer = true;
}
delete vertexDefinition;
//renderState->mCullMode = CullMode_Front;
renderState->mTexWrap = true;
renderState->mDepthFunc = DepthFunc_LessEqual;
renderState->mWriteDepthBuffer = true;
dxModelInstance->mRenderState = renderState;
////
@ -1052,7 +1064,8 @@ DXModelInstance::~DXModelInstance()
void DXModelInstance::Render(RenderDevice* renderDevice, RenderWindow* renderWindow)
{
SetRenderState();
if (mRenderState != NULL)
SetRenderState();
for (int meshIdx = 0; meshIdx < (int)mDXModelMeshs.size(); meshIdx++)
{
@ -1064,28 +1077,7 @@ void DXModelInstance::Render(RenderDevice* renderDevice, RenderWindow* renderWin
for (auto primIdx = 0; primIdx < (int)dxMesh->mPrimitives.size(); primIdx++)
{
auto dxPrimitives = &dxMesh->mPrimitives[primIdx];
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;
@ -1103,14 +1095,12 @@ void DXModelInstance::Render(RenderDevice* renderDevice, RenderWindow* renderWin
}
void Beefy::DXModelInstance::CommandQueued(DrawLayer* drawLayer)
{
#ifndef BF_NO_FBX
{
mRenderState = drawLayer->mRenderDevice->mCurRenderState;
BF_ASSERT(mRenderState->mShader->mVertexSize == sizeof(DXModelVertex));
drawLayer->mCurTextures[0] = NULL;
#ifndef BF_NO_FBX
ModelAnimation* fbxAnim = &mModelDef->mAnims[0];
Matrix4 jointsMatrices[BF_MAX_NUM_BONES];
@ -1560,8 +1550,7 @@ bool DXRenderDevice::Init(BFApp* app)
rasterizerState.AntialiasedLineEnable = false;
mD3DDevice->CreateRasterizerState(&rasterizerState, &dxRenderState->mD3DRasterizerState);
mD3DDeviceContext->RSSetState(dxRenderState->mD3DRasterizerState);
mD3DDeviceContext->RSSetState(dxRenderState->mD3DRasterizerState);
mD3DDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D11BlendState* g_pBlendState = NULL;

View file

@ -95,7 +95,7 @@ typedef std::map<String, DXShaderParam*> DXShaderParamMap;
class DXShader : public Shader
{
public:
public:
ID3D11InputLayout* mD3DLayout;
ID3D11VertexShader* mD3DVertexShader;
ID3D11PixelShader* mD3DPixelShader;
@ -302,7 +302,7 @@ public:
virtual void PhysSetRenderWindow(RenderWindow* renderWindow);
virtual void PhysSetRenderTarget(Texture* renderTarget) override;
virtual RenderState* CreateRenderState(RenderState* srcRenderState) override;
virtual ModelInstance* CreateModelInstance(ModelDef* modelDef) override;
virtual ModelInstance* CreateModelInstance(ModelDef* modelDef, ModelCreateFlags flags) override;
public:
DXRenderDevice();

View file

@ -0,0 +1,145 @@
#include "MathUtils.h"
#include "Sphere.h"
USING_NS_BF;
bool Beefy::RayIntersectsTriangle(const Vector3& rayOrigin, const Vector3& rayVector, const Vector3& vtx0, const Vector3& vtx1, const Vector3& vtx2, Vector3* outIntersectionPoint, float* outDistance)
{
const float EPSILON = 0.0000001f;
Vector3 edge1, edge2, h, s, q;
float a, f, u, v;
edge1 = vtx1 - vtx0;
edge2 = vtx2 - vtx0;
h = Vector3::CrossProduct(rayVector, edge2);//rayVector.crossProduct(edge2);
a = Vector3::Dot(edge1, h); //edge1.dotProduct(h);
if (a > -EPSILON && a < EPSILON)
return false; // This ray is parallel to this triangle.
f = 1.0f / a;
s = rayOrigin - vtx0;
u = f * Vector3::Dot(s, h); //s.dotProduct(h);
if (u < 0.0 || u > 1.0)
return false;
q = Vector3::CrossProduct(s, edge1); //s.crossProduct(edge1);
v = f * Vector3::Dot(rayVector, q); //rayVector.dotProduct(q);
if (v < 0.0 || u + v > 1.0)
return false;
// At this stage we can compute t to find out where the intersection point is on the line.
float distance = f * Vector3::Dot(edge2, q); //edge2.dotProduct(q);
if (distance > EPSILON) // ray intersection
{
if (outIntersectionPoint != NULL)
*outIntersectionPoint = rayOrigin + rayVector * distance;
if (outDistance != NULL)
*outDistance = distance;
return true;
}
else // This means that there is a line intersection but not a ray intersection.
return false;
}
bool Beefy::RayIntersectsCircle(const Vector3& rayOrigin, const Vector3& rayVector, const Sphere& sphere, Vector3* outIntersectionPoint, Vector3* outNormal, float* outDistance)
{
Vector3 e = sphere.mCenter - rayOrigin;
float rSq = sphere.mRadius * sphere.mRadius;
float eSq = e.GetMagnitudeSquare();
float a = Vector3::Dot(e, rayVector); // ray.direction is assumed to be normalized
float bSq = /*sqrtf(*/eSq - (a * a)/*)*/;
float f = sqrtf(fabsf((rSq)- /*(b * b)*/bSq));
// Assume normal intersection!
float t = a - f;
// No collision has happened
if (rSq - (eSq - a * a) < 0.0f)
{
return false;
}
// Ray starts inside the sphere
else if (eSq < rSq)
{
// Just reverse direction
t = a + f;
}
if (outDistance != NULL)
*outDistance = t;
if ((outIntersectionPoint != NULL) || (outNormal != NULL))
{
Vector3 intersect = rayOrigin + rayVector * t;
if (outIntersectionPoint != NULL)
*outIntersectionPoint = intersect;
if (outNormal != NULL)
*outNormal = Vector3::Normalize(intersect - sphere.mCenter);
}
return true;
}
bool Beefy::RayIntersectsAABB(const Vector3& rayOrigin, const Vector3& rayVector, const AABB& aabb, Vector3* outIntersectionPoint, Vector3* outNormal, float* outDistance)
{
const Vector3& min = aabb.mMin;
const Vector3& max = aabb.mMax;
// Any component of direction could be 0!
// Address this by using a small number, close to
// 0 in case any of directions components are 0
float t1 = (min.mX - rayOrigin.mX) / ((fabs(rayVector.mX) < 0.00001f) ? 0.00001f : rayVector.mX);
float t2 = (max.mX - rayOrigin.mX) / ((fabs(rayVector.mX) < 0.00001f) ? 0.00001f : rayVector.mX);
float t3 = (min.mY - rayOrigin.mY) / ((fabs(rayVector.mY) < 0.00001f) ? 0.00001f : rayVector.mY);
float t4 = (max.mY - rayOrigin.mY) / ((fabs(rayVector.mY) < 0.00001f) ? 0.00001f : rayVector.mY);
float t5 = (min.mZ - rayOrigin.mZ) / ((fabs(rayVector.mZ) < 0.00001f) ? 0.00001f : rayVector.mZ);
float t6 = (max.mZ - rayOrigin.mZ) / ((fabs(rayVector.mZ) < 0.00001f) ? 0.00001f : rayVector.mZ);
float tmin = fmaxf(fmaxf(fminf(t1, t2), fminf(t3, t4)), fminf(t5, t6));
float tmax = fminf(fminf(fmaxf(t1, t2), fmaxf(t3, t4)), fmaxf(t5, t6));
// if tmax < 0, ray is intersecting AABB
// but entire AABB is being it's origin
if (tmax < 0) {
return false;
}
// if tmin > tmax, ray doesn't intersect AABB
if (tmin > tmax) {
return false;
}
float t_result = tmin;
// If tmin is < 0, tmax is closer
if (tmin < 0.0f) {
t_result = tmax;
}
if ((outIntersectionPoint != NULL) || (outDistance != NULL))
{
Vector3 hitPoint = rayOrigin + rayVector * t_result;
if (outIntersectionPoint != NULL)
*outIntersectionPoint = hitPoint;
if (outDistance != NULL)
*outDistance = (rayOrigin - hitPoint).GetMagnitude();
}
if (outNormal != NULL)
{
static Vector3 normals[] = {
Vector3(-1, 0, 0),
Vector3(1, 0, 0),
Vector3(0, -1, 0),
Vector3(0, 1, 0),
Vector3(0, 0, -1),
Vector3(0, 0, 1)
};
float t[] = { t1, t2, t3, t4, t5, t6 };
for (int i = 0; i < 6; ++i)
{
if (t_result == t[i])
*outNormal = normals[i];
}
}
return true;
}

View file

@ -0,0 +1,21 @@
#pragma once
#include "Vector.h"
#include "Matrix4.h"
NS_BF_BEGIN
class AABB
{
public:
Vector3 mMin;
Vector3 mMax;
};
class Sphere;
bool RayIntersectsTriangle(const Vector3& rayOrigin, const Vector3& rayVector, const Vector3& vtx0, const Vector3& vtx1, const Vector3& vtx2, Vector3* outIntersectionPoint, float* distance);
bool RayIntersectsCircle(const Vector3& rayOrigin, const Vector3& rayVector, const Sphere& sphere, Vector3* outIntersectionPoint, Vector3* outNormal, float* outDistance);
bool RayIntersectsAABB(const Vector3& rayOrigin, const Vector3& rayVector, const AABB& aabb, Vector3* outIntersectionPoint, Vector3* outNormal, float* outDistance);
NS_BF_END

View file

@ -109,6 +109,15 @@ public:
}
static Matrix4 CreateTransform(const Vector3& position, const Vector3& scale, const Quaternion& orientation);
static float Determinant(float m11, float m12, float m13,
float m21, float m22, float m23,
float m31, float m32, float m33)
{
return m11 * (m22 * m33 - m32 * m23) -
m21 * (m12 * m33 - m32 * m13) +
m31 * (m12 * m23 - m22 * m13);
}
};
NS_BF_END;

195
BeefySysLib/util/Sphere.cpp Normal file
View file

@ -0,0 +1,195 @@
#include "Sphere.h"
#include "Matrix4.h"
USING_NS_BF;
static const float radiusEpsilon = 1e-4f; // NOTE: To avoid numerical inaccuracies
Sphere::Sphere()
{
mRadius = -1;
}
Sphere::Sphere(const Sphere& S)
{
mRadius = S.mRadius;
mCenter = S.mCenter;
}
Sphere::Sphere(const Vector3& O)
{
mRadius = 0 + radiusEpsilon;
mCenter = O;
}
Sphere::Sphere(const Vector3& O, float R)
{
mRadius = R;
mCenter = O;
}
Sphere::Sphere(const Vector3& O, const Vector3& A)
{
Vector3 a = A - O;
Vector3 o = a * 0.5f;
mRadius = o.GetMagnitude() + radiusEpsilon;
mCenter = O + o;
}
Sphere::Sphere(const Vector3& O, const Vector3& A, const Vector3& B)
{
Vector3 a = A - O;
Vector3 b = B - O;
Vector3 axb = Vector3::CrossProduct(a, b);
float Denominator = 2.0f * Vector3::Dot(axb, axb);
Vector3 o =
((Vector3::CrossProduct(axb, a) * Vector3::Dot(b, b)) +
(Vector3::CrossProduct(b, axb) * Vector3::Dot(a, a))) / Denominator;
mRadius = o.GetMagnitude() + radiusEpsilon;
mCenter = O + o;
}
Sphere::Sphere(const Vector3& O, const Vector3& A, const Vector3& B, const Vector3& C)
{
Vector3 a = A - O;
Vector3 b = B - O;
Vector3 c = C - O;
float Denominator = 2.0f * Matrix4::Determinant(
a.mX, a.mY, a.mZ,
b.mX, b.mY, b.mZ,
c.mX, c.mY, c.mZ);
Vector3 o = (
(Vector3::CrossProduct(a, b) * Vector3::Dot(c, c)) +
(Vector3::CrossProduct(c, a) * Vector3::Dot(b, b)) +
(Vector3::CrossProduct(b, c) * Vector3::Dot(a, a))) / Denominator;
mRadius = o.GetMagnitude() + radiusEpsilon;
mCenter = O + o;
}
Sphere& Sphere::operator=(const Sphere& S)
{
mRadius = S.mRadius;
mCenter = S.mCenter;
return *this;
}
float Sphere::GetDistance(const Vector3& P) const
{
return Vector3::GetDistance(P, mCenter) - mRadius;
}
float Sphere::GetDistanceSquare(const Vector3& P) const
{
return Vector3::GetDistanceSquare(P, mCenter) - mRadius * mRadius;
}
float Sphere::GetDistance(const Sphere& S, const Vector3& P)
{
return Vector3::GetDistance(P, S.mCenter) - S.mRadius;
}
float Sphere::GetDistance(const Vector3& P, const Sphere& S)
{
return Vector3::GetDistance(P, S.mCenter) - S.mRadius;
}
float Sphere::GetDistanceSquare(const Sphere& S, const Vector3& P)
{
return Vector3::GetDistanceSquare(P, S.mCenter) - S.mRadius * S.mRadius;
}
float Sphere::GetDistanceSquare(const Vector3& P, const Sphere& S)
{
return Vector3::GetDistanceSquare(P, S.mCenter) - S.mRadius * S.mRadius;
}
Sphere Sphere::RecurseMini(Vector3* P[], int p, int b)
{
Sphere MB;
switch (b)
{
case 0:
MB = Sphere();
break;
case 1:
MB = Sphere(*P[-1]);
break;
case 2:
MB = Sphere(*P[-1], *P[-2]);
break;
case 3:
MB = Sphere(*P[-1], *P[-2], *P[-3]);
break;
case 4:
MB = Sphere(*P[-1], *P[-2], *P[-3], *P[-4]);
return MB;
}
for (int i = 0; i < p; i++)
{
if (MB.GetDistanceSquare(*P[i]) > 0) // Signed square distance to sphere
{
for (int j = i; j > 0; j--)
{
Vector3* T = P[j];
P[j] = P[j - 1];
P[j - 1] = T;
}
MB = RecurseMini(P + 1, i, b + 1);
}
}
return MB;
}
Sphere Sphere::MiniBall(Vector3 P[], int p)
{
Vector3** L = new Vector3* [p];
for (int i = 0; i < p; i++)
L[i] = &P[i];
Sphere MB = RecurseMini(L, p);
delete[] L;
return MB;
}
Sphere Sphere::SmallBall(Vector3 P[], int p)
{
Vector3 mCenter;
float mRadius = -1;
if (p > 0)
{
for (int i = 0; i < p; i++)
mCenter += P[i];
mCenter /= (float)p;
for (int i = 0; i < p; i++)
{
float d2 = Vector3::GetDistanceSquare(P[i], mCenter);
if (d2 > mRadius)
mRadius = d2;
}
mRadius = sqrtf(mRadius) + radiusEpsilon;
}
return Sphere(mCenter, mRadius);
}

43
BeefySysLib/util/Sphere.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
#include "Common.h"
#include "Vector.h"
NS_BF_BEGIN
class Vector3;
class Matrix4;
class Sphere
{
public:
Vector3 mCenter;
float mRadius;
Sphere();
Sphere(const Sphere& X);
Sphere(const Vector3& O); // Point-Sphere
Sphere(const Vector3& O, float R); // Center and radius (not squared)
Sphere(const Vector3& O, const Vector3& A); // Sphere through two points
Sphere(const Vector3& O, const Vector3& A, const Vector3& B); // Sphere through three points
Sphere(const Vector3& O, const Vector3& A, const Vector3& B, const Vector3& C); // Sphere through four points
Sphere& operator=(const Sphere& S);
float GetDistance(const Vector3& P) const; // Distance from p to boundary of the Sphere
float GetDistanceSquare(const Vector3& P) const; // Square distance from p to boundary of the Sphere
static float GetDistance(const Sphere& S, const Vector3& P); // Distance from p to boundary of the Sphere
static float GetDistance(const Vector3& P, const Sphere& S); // Distance from p to boundary of the Sphere
static float GetDistanceSquare(const Sphere& S, const Vector3& P); // Square distance from p to boundary of the Sphere
static float GetDistanceSquare(const Vector3& P, const Sphere& S); // Square distance from p to boundary of the Sphere
static Sphere MiniBall(Vector3 P[], int p); // Smallest enclosing sphere
static Sphere SmallBall(Vector3 P[], int p); // Enclosing sphere approximation
private:
static Sphere RecurseMini(Vector3* P[], int p, int b = 0);
};
NS_BF_END

View file

@ -4,6 +4,13 @@
USING_NS_BF;
Vector3::Vector3()
{
mX = 0;
mY = 0;
mZ = 0;
}
Vector3::Vector3(float x, float y, float z)
{
mX = x;
@ -16,6 +23,11 @@ float Vector3::GetMagnitude() const
return sqrtf(mX*mX + mY*mY + mZ*mZ);
}
float Vector3::GetMagnitudeSquare() const
{
return mX * mX + mY * mY + mZ * mZ;
}
Vector3 Vector3::Normalize(const Vector3& vec)
{
float mag = vec.GetMagnitude();
@ -39,6 +51,14 @@ Vector3 Vector3::CrossProduct(const Vector3& vec1, const Vector3& vec2)
}
Vector3 Vector3::Transform(const Vector3& vec, const Matrix4& matrix)
{
return Vector3(
(matrix.m00 * vec.mX + matrix.m01 * vec.mY + matrix.m02 * vec.mZ + matrix.m03),
(matrix.m10 * vec.mX + matrix.m11 * vec.mY + matrix.m12 * vec.mZ + matrix.m13),
(matrix.m20 * vec.mX + matrix.m21 * vec.mY + matrix.m22 * vec.mZ + matrix.m23));
}
Vector3 Vector3::TransformW(const Vector3& vec, const Matrix4& matrix)
{
float fInvW = 1.0f / (matrix.m30 * vec.mX + matrix.m31 * vec.mY + matrix.m32 * vec.mZ + matrix.m33);

View file

@ -36,13 +36,25 @@ public:
float mZ;
public:
Vector3(float x = 0, float y = 0, float z = 0);
Vector3();
Vector3(float x, float y, float z);
float GetMagnitude() const;
float GetMagnitudeSquare() const;
static Vector3 Normalize(const Vector3& vec);
static float Dot(const Vector3& vec1, const Vector3& vec2);
static Vector3 CrossProduct(const Vector3& vec1, const Vector3& vec2);
static float GetDistance(const Vector3& v0, const Vector3& v1)
{
return (v0 - v1).GetMagnitude();
}
static float GetDistanceSquare(const Vector3& v0, const Vector3& v1)
{
return (v0 - v1).GetMagnitudeSquare();
}
bool operator==(const Vector3& check) const
{
return (mX == check.mX) && (mY == check.mY) && (mZ == check.mZ);
@ -54,8 +66,9 @@ public:
}
static Vector3 Transform(const Vector3& vec, const Matrix4& matrix);
static Vector3 TransformW(const Vector3& vec, const Matrix4& matrix);
static Vector3 Transform(const Vector3& vec, const Quaternion& quat);
static Vector3 Transform2(const Vector3& vec, const Quaternion& quat);
static Vector3 Transform2(const Vector3& vec, const Quaternion& quat);
static Vector3 Scale(const Vector3& vec, float scale)
{
@ -77,6 +90,24 @@ public:
return Vector3(mX * scale, mY * scale, mZ * scale);
}
Vector3 operator /(float scale) const
{
return Vector3(mX / scale, mY / scale, mZ / scale);
}
float operator^(const Vector3& v) // Angle between vectors
{
return acosf(Dot(*this / this->GetMagnitude(), v / v.GetMagnitude()));
}
inline Vector3& operator += (const Vector3& vec)
{
mX += vec.mX;
mY += vec.mY;
mZ += vec.mZ;
return *this;
}
inline Vector3& operator -= (const Vector3& vec)
{
mX -= vec.mX;
@ -85,6 +116,40 @@ public:
return *this;
}
inline Vector3& operator *= (float num)
{
mX *= num;
mY *= num;
mZ *= num;
return *this;
}
inline Vector3& operator /= (float num)
{
mX /= num;
mY /= num;
mZ /= num;
return *this;
}
inline Vector3 operator - (const Vector3& vec) const
{
Vector3 result;
result.mX = mX - vec.mX;
result.mY = mY - vec.mY;
result.mZ = mZ - vec.mZ;
return result;
}
inline Vector3 operator + (const Vector3& vec)
{
Vector3 result;
result.mX = mX + vec.mX;
result.mY = mY + vec.mY;
result.mZ = mZ + vec.mZ;
return result;
}
inline Vector3& operator *= (const Vector3& vec)
{
mX *= vec.mX;