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:
parent
369bb0640c
commit
39c140f44a
27 changed files with 4063 additions and 126 deletions
|
@ -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);
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
145
BeefySysLib/util/MathUtils.cpp
Normal file
145
BeefySysLib/util/MathUtils.cpp
Normal 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;
|
||||
}
|
21
BeefySysLib/util/MathUtils.h
Normal file
21
BeefySysLib/util/MathUtils.h
Normal 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
|
|
@ -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
195
BeefySysLib/util/Sphere.cpp
Normal 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
43
BeefySysLib/util/Sphere.h
Normal 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
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue