You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1911 lines
63 KiB
C++
1911 lines
63 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
#include "RenderDll_precompiled.h"
|
|
#include "DriverD3D.h"
|
|
#include "D3DRenderAuxGeom.h"
|
|
#include <Pak/CryPakUtils.h>
|
|
|
|
#if defined(ENABLE_RENDER_AUX_GEOM)
|
|
|
|
const float c_clipThres(0.1f);
|
|
|
|
enum EAuxGeomBufferSizes
|
|
{
|
|
e_auxGeomVBSize = 0xffff,
|
|
e_auxGeomIBSize = e_auxGeomVBSize * 2 * 3
|
|
};
|
|
|
|
|
|
|
|
struct SAuxObjVertex
|
|
{
|
|
SAuxObjVertex()
|
|
{
|
|
}
|
|
|
|
SAuxObjVertex(const Vec3& pos, const Vec3& normal)
|
|
: m_pos(pos)
|
|
, m_normal(normal)
|
|
{
|
|
}
|
|
|
|
Vec3 m_pos;
|
|
Vec3 m_normal;
|
|
};
|
|
|
|
|
|
typedef std::vector< SAuxObjVertex > AuxObjVertexBuffer;
|
|
typedef std::vector< uint16 > AuxObjIndexBuffer;
|
|
|
|
|
|
CRenderAuxGeomD3D::CRenderAuxGeomD3D(CD3D9Renderer& renderer)
|
|
: m_renderer(renderer)
|
|
, m_pAuxGeomVB(0)
|
|
, m_pAuxGeomIB(0)
|
|
, m_pCurVB(0)
|
|
, m_pCurIB(0)
|
|
, m_auxGeomSBM()
|
|
, m_wndXRes(0)
|
|
, m_wndYRes(0)
|
|
, m_aspect(1.0f)
|
|
, m_aspectInv(1.0f)
|
|
, m_matrices()
|
|
, m_curPrimType(CAuxGeomCB::e_PrimTypeInvalid)
|
|
, m_curPointSize(1)
|
|
, m_curTransMatrixIdx(-1)
|
|
, m_pAuxGeomShader(0)
|
|
, m_curDrawInFrontMode(e_DrawInFrontOff)
|
|
, m_auxSortedPushBuffer()
|
|
, m_pCurCBRawData(0)
|
|
, m_auxGeomCBCol()
|
|
, CV_r_auxGeom(1)
|
|
{
|
|
REGISTER_CVAR2("r_auxGeom", &CV_r_auxGeom, 1, VF_NULL, "");
|
|
}
|
|
|
|
|
|
CRenderAuxGeomD3D::~CRenderAuxGeomD3D()
|
|
{
|
|
//SAFE_RELEASE(m_pAuxGeomShader);
|
|
// m_pAuxGeomShader released by CShaderMan ???
|
|
//delete m_pAuxGeomShader;
|
|
//m_pAuxGeomShader = 0;
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::GetMemoryUsage(ICrySizer* pSizer) const
|
|
{
|
|
pSizer->AddObject((char*)this - 16, sizeof(*this) + 16); // adjust for new operator
|
|
pSizer->AddObject(m_auxSortedPushBuffer);
|
|
pSizer->AddObject(m_auxGeomCBCol);
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::ReleaseDeviceObjects()
|
|
{
|
|
gcpRendD3D->m_DevMan.ReleaseD3D11Buffer(m_pAuxGeomVB);
|
|
m_pAuxGeomVB = nullptr;
|
|
gcpRendD3D->m_DevMan.ReleaseD3D11Buffer(m_pAuxGeomIB);
|
|
m_pAuxGeomIB = nullptr;
|
|
|
|
for (uint32 i(0); i < e_auxObjNumLOD; ++i)
|
|
{
|
|
m_sphereObj[ i ].Release();
|
|
m_diskObj[ i ].Release();
|
|
m_quadObj[ i ].Release();
|
|
m_coneObj[ i ].Release();
|
|
m_cylinderObj[ i ].Release();
|
|
}
|
|
}
|
|
|
|
int CRenderAuxGeomD3D::GetDeviceDataSize()
|
|
{
|
|
int nSize = 0;
|
|
|
|
nSize += _VertBufferSize(m_pAuxGeomVB);
|
|
nSize += _IndexBufferSize(m_pAuxGeomIB);
|
|
|
|
for (uint32 i = 0; i < e_auxObjNumLOD; ++i)
|
|
{
|
|
nSize += m_sphereObj[i].GetDeviceDataSize();
|
|
nSize += m_diskObj[i].GetDeviceDataSize();
|
|
nSize += m_quadObj[i].GetDeviceDataSize();
|
|
nSize += m_coneObj[i].GetDeviceDataSize();
|
|
nSize += m_cylinderObj[i].GetDeviceDataSize();
|
|
}
|
|
return nSize;
|
|
}
|
|
|
|
|
|
// function to generate a sphere mesh
|
|
static void CreateSphere(AuxObjVertexBuffer& vb, AuxObjIndexBuffer& ib, float radius, unsigned int rings, unsigned int sections)
|
|
{
|
|
// calc required number of vertices/indices/triangles to build a sphere for the given parameters
|
|
uint32 numVertices((rings - 1) * (sections + 1) + 2);
|
|
uint32 numTriangles((rings - 2) * sections * 2 + 2 * sections);
|
|
uint32 numIndices(numTriangles * 3);
|
|
|
|
// setup buffers
|
|
vb.clear();
|
|
vb.reserve(numVertices);
|
|
|
|
ib.clear();
|
|
ib.reserve(numIndices);
|
|
|
|
// 1st pole vertex
|
|
vb.push_back(SAuxObjVertex(Vec3(0.0f, 0.0f, radius), Vec3(0.0f, 0.0f, 1.0f)));
|
|
|
|
// calculate "inner" vertices
|
|
float sectionSlice(DEG2RAD(360.0f / (float) sections));
|
|
float ringSlice(DEG2RAD(180.0f / (float) rings));
|
|
|
|
for (uint32 a(1); a < rings; ++a)
|
|
{
|
|
float w(sinf(a * ringSlice));
|
|
for (uint32 i(0); i <= sections; ++i)
|
|
{
|
|
Vec3 v;
|
|
v.x = radius * cosf(i * sectionSlice) * w;
|
|
v.y = radius * sinf(i * sectionSlice) * w;
|
|
v.z = radius * cosf(a * ringSlice);
|
|
vb.push_back(SAuxObjVertex(v, v.GetNormalized()));
|
|
}
|
|
}
|
|
|
|
// 2nd vertex of pole (for end cap)
|
|
vb.push_back(SAuxObjVertex(Vec3(0.0f, 0.0f, -radius), Vec3(0.0f, 0.0f, 1.0f)));
|
|
|
|
// build "inner" faces
|
|
for (uint32 a(0); a < rings - 2; ++a)
|
|
{
|
|
for (uint32 i(0); i < sections; ++i)
|
|
{
|
|
ib.push_back((uint16) (1 + a * (sections + 1) + i + 1));
|
|
ib.push_back((uint16) (1 + a * (sections + 1) + i));
|
|
ib.push_back((uint16) (1 + (a + 1) * (sections + 1) + i + 1));
|
|
|
|
ib.push_back((uint16) (1 + (a + 1) * (sections + 1) + i));
|
|
ib.push_back((uint16) (1 + (a + 1) * (sections + 1) + i + 1));
|
|
ib.push_back((uint16) (1 + a * (sections + 1) + i));
|
|
}
|
|
}
|
|
|
|
// build faces for end caps (to connect "inner" vertices with poles)
|
|
for (uint32 i(0); i < sections; ++i)
|
|
{
|
|
ib.push_back((uint16) (1 + (0) * (sections + 1) + i));
|
|
ib.push_back((uint16) (1 + (0) * (sections + 1) + i + 1));
|
|
ib.push_back((uint16) 0);
|
|
}
|
|
|
|
for (uint32 i(0); i < sections; ++i)
|
|
{
|
|
ib.push_back((uint16) (1 + (rings - 2) * (sections + 1) + i + 1));
|
|
ib.push_back((uint16) (1 + (rings - 2) * (sections + 1) + i));
|
|
ib.push_back((uint16) ((rings - 1) * (sections + 1) + 1));
|
|
}
|
|
}
|
|
|
|
// function to generate a disk mesh
|
|
static void CreateDisk(AuxObjVertexBuffer& vb, AuxObjIndexBuffer& ib, float radius, unsigned int sections)
|
|
{
|
|
// calc required number of vertices/indices/triangles to build a disk for the given parameters
|
|
uint32 numVertices = (sections + 1) * 2;
|
|
uint32 numTriangles = sections * 2;
|
|
uint32 numIndices = numTriangles * 3;
|
|
|
|
// setup buffers
|
|
vb.clear();
|
|
vb.reserve(numVertices);
|
|
|
|
ib.clear();
|
|
ib.reserve(numIndices);
|
|
|
|
Vec3 yUp = Vec3(0.0f, 1.0f, 0.0f);
|
|
Vec3 yDown = Vec3(0.0f, -1.0f, 0.0f);
|
|
|
|
// center vertex
|
|
vb.push_back(SAuxObjVertex(Vec3(0.0f, 0.0f, 0.0f), yUp));
|
|
vb.push_back(SAuxObjVertex(Vec3(0.0f, 0.0f, 0.0f), yDown));
|
|
|
|
// create circle around it
|
|
float sectionSlice(DEG2RAD(360.0f / (float)sections));
|
|
for (uint32 i(0); i <= sections; ++i)
|
|
{
|
|
Vec3 v;
|
|
v.x = radius * cosf(i * sectionSlice);
|
|
v.y = 0.0f;
|
|
v.z = radius * sinf(i * sectionSlice);
|
|
vb.push_back(SAuxObjVertex(v, yUp));
|
|
vb.push_back(SAuxObjVertex(v, yDown));
|
|
}
|
|
|
|
// build faces
|
|
for (uint16 i = 0; i < numTriangles; i += 2)
|
|
{
|
|
// top face
|
|
ib.push_back(0);
|
|
ib.push_back(2 + i + 2);
|
|
ib.push_back(2 + i);
|
|
|
|
// bottom face
|
|
ib.push_back(1);
|
|
ib.push_back(3 + i);
|
|
ib.push_back(3 + i + 2);
|
|
}
|
|
}
|
|
|
|
// function to generate a quad mesh on the x z plane
|
|
static void CreateQuad(AuxObjVertexBuffer& vb, AuxObjIndexBuffer& ib, float width, float height)
|
|
{
|
|
// Calc required number of vertices/indices/triangles to build a quad for the given parameters
|
|
uint32 numVertices = 4 * 2; // 4 corners * 2 sides
|
|
uint32 numTriangles = 2 * 2; // 2 triangles * 2 sides
|
|
uint32 numIndices = numTriangles * 3;
|
|
|
|
float halfWidth = width * 0.5f;
|
|
float halfHeight = height * 0.5f;
|
|
|
|
// setup buffers
|
|
vb.clear();
|
|
vb.reserve(numVertices);
|
|
|
|
ib.clear();
|
|
ib.reserve(numIndices);
|
|
|
|
Vec3 yUp = Vec3(0.0f, 1.0f, 0.0f);
|
|
Vec3 yDown = Vec3(0.0f, -1.0f, 0.0f);
|
|
|
|
// top faces
|
|
vb.push_back(SAuxObjVertex(Vec3(-halfWidth, 0.0f, halfHeight), yUp));
|
|
vb.push_back(SAuxObjVertex(Vec3( halfWidth, 0.0f, halfHeight), yUp));
|
|
vb.push_back(SAuxObjVertex(Vec3(-halfWidth, 0.0f, -halfHeight), yUp));
|
|
vb.push_back(SAuxObjVertex(Vec3( halfWidth, 0.0f, -halfHeight), yUp));
|
|
|
|
ib.insert(ib.end(), {1, 2, 0, 3, 2, 1});
|
|
|
|
// bottom faces
|
|
vb.push_back(SAuxObjVertex(Vec3(-halfWidth, 0.0f, halfHeight), yDown));
|
|
vb.push_back(SAuxObjVertex(Vec3( halfWidth, 0.0f, halfHeight), yDown));
|
|
vb.push_back(SAuxObjVertex(Vec3(-halfWidth, 0.0f, -halfHeight), yDown));
|
|
vb.push_back(SAuxObjVertex(Vec3( halfWidth, 0.0f, -halfHeight), yDown));
|
|
|
|
ib.insert(ib.end(), { 4, 6, 5, 5, 6, 7 });
|
|
}
|
|
|
|
// function to generate a cone mesh
|
|
static void CreateCone(AuxObjVertexBuffer& vb, AuxObjIndexBuffer& ib, float radius, float height, unsigned int sections)
|
|
{
|
|
// calc required number of vertices/indices/triangles to build a cone for the given parameters
|
|
uint32 numVertices(2 * (sections + 1) + 2);
|
|
uint32 numTriangles(2 * sections);
|
|
uint32 numIndices(numTriangles * 3);
|
|
|
|
// setup buffers
|
|
vb.clear();
|
|
vb.reserve(numVertices);
|
|
|
|
ib.clear();
|
|
ib.reserve(numIndices);
|
|
|
|
// center vertex
|
|
vb.push_back(SAuxObjVertex(Vec3(0.0f, 0.0f, 0.0f), Vec3(0.0f, -1.0f, 0.0f)));
|
|
|
|
// create circle around it
|
|
float sectionSlice(DEG2RAD(360.0f / (float) sections));
|
|
for (uint32 i(0); i <= sections; ++i)
|
|
{
|
|
Vec3 v;
|
|
v.x = radius * cosf(i * sectionSlice);
|
|
v.y = 0.0f;
|
|
v.z = radius * sinf(i * sectionSlice);
|
|
vb.push_back(SAuxObjVertex(v, Vec3(0.0f, -1.0f, 0.0f)));
|
|
}
|
|
|
|
// build faces for end cap
|
|
for (uint16 i(0); i < sections; ++i)
|
|
{
|
|
ib.push_back(0);
|
|
ib.push_back(1 + i);
|
|
ib.push_back(1 + i + 1);
|
|
}
|
|
|
|
// top
|
|
vb.push_back(SAuxObjVertex(Vec3(0.0f, height, 0.0f), Vec3(0.0f, 1.0f, 0.0f)));
|
|
|
|
for (uint32 i(0); i <= sections; ++i)
|
|
{
|
|
Vec3 v;
|
|
v.x = radius * cosf(i * sectionSlice);
|
|
v.y = 0.0f;
|
|
v.z = radius * sinf(i * sectionSlice);
|
|
|
|
Vec3 v1;
|
|
v1.x = radius * cosf(i * sectionSlice + 0.01f);
|
|
v1.y = 0.0f;
|
|
v1.z = radius * sinf(i * sectionSlice + 0.01f);
|
|
|
|
Vec3 d(v1 - v);
|
|
Vec3 d1(Vec3(0.0, height, 0.0f) - v);
|
|
|
|
Vec3 n((d1.Cross(d)).normalized());
|
|
vb.push_back(SAuxObjVertex(v, n));
|
|
}
|
|
|
|
// build faces
|
|
for (uint16 i(0); i < sections; ++i)
|
|
{
|
|
ib.push_back(sections + 2);
|
|
ib.push_back(sections + 3 + i + 1);
|
|
ib.push_back(sections + 3 + i);
|
|
}
|
|
}
|
|
|
|
|
|
// function to generate a cylinder mesh
|
|
static void CreateCylinder(AuxObjVertexBuffer& vb, AuxObjIndexBuffer& ib, float radius, float height, unsigned int sections)
|
|
{
|
|
// calc required number of vertices/indices/triangles to build a cylinder for the given parameters
|
|
uint32 numVertices(4 * (sections + 1) + 2);
|
|
uint32 numTriangles(4 * sections);
|
|
uint32 numIndices(numTriangles * 3);
|
|
|
|
// setup buffers
|
|
vb.clear();
|
|
vb.reserve(numVertices);
|
|
|
|
ib.clear();
|
|
ib.reserve(numIndices);
|
|
|
|
float sectionSlice(DEG2RAD(360.0f / (float) sections));
|
|
|
|
// bottom cap
|
|
{
|
|
// center bottom vertex
|
|
vb.push_back(SAuxObjVertex(Vec3(0.0f, -0.5f * height, 0.0f), Vec3(0.0f, -1.0f, 0.0f)));
|
|
|
|
// create circle around it
|
|
for (uint32 i(0); i <= sections; ++i)
|
|
{
|
|
Vec3 v;
|
|
v.x = radius * cosf(i * sectionSlice);
|
|
v.y = -0.5f * height;
|
|
v.z = radius * sinf(i * sectionSlice);
|
|
vb.push_back(SAuxObjVertex(v, Vec3(0.0f, -1.0f, 0.0f)));
|
|
}
|
|
|
|
// build faces
|
|
for (uint16 i(0); i < sections; ++i)
|
|
{
|
|
ib.push_back(0);
|
|
ib.push_back(1 + i);
|
|
ib.push_back(1 + i + 1);
|
|
}
|
|
}
|
|
|
|
// side
|
|
{
|
|
int vIdx(vb.size());
|
|
|
|
for (uint32 i(0); i <= sections; ++i)
|
|
{
|
|
Vec3 v;
|
|
v.x = radius * cosf(i * sectionSlice);
|
|
v.y = -0.5f * height;
|
|
v.z = radius * sinf(i * sectionSlice);
|
|
|
|
Vec3 n(v.normalized());
|
|
vb.push_back(SAuxObjVertex(v, n));
|
|
vb.push_back(SAuxObjVertex(Vec3(v.x, -v.y, v.z), n));
|
|
}
|
|
|
|
// build faces
|
|
for (uint16 i(0); i < sections; ++i, vIdx += 2)
|
|
{
|
|
ib.push_back(vIdx);
|
|
ib.push_back(vIdx + 1);
|
|
ib.push_back(vIdx + 2);
|
|
|
|
ib.push_back(vIdx + 1);
|
|
ib.push_back(vIdx + 3);
|
|
ib.push_back(vIdx + 2);
|
|
}
|
|
}
|
|
|
|
// top cap
|
|
{
|
|
int vIdx(vb.size());
|
|
|
|
// center top vertex
|
|
vb.push_back(SAuxObjVertex(Vec3(0.0f, 0.5f * height, 0.0f), Vec3(0.0f, 1.0f, 0.0f)));
|
|
|
|
// create circle around it
|
|
for (uint32 i(0); i <= sections; ++i)
|
|
{
|
|
Vec3 v;
|
|
v.x = radius * cosf(i * sectionSlice);
|
|
v.y = 0.5f * height;
|
|
v.z = radius * sinf(i * sectionSlice);
|
|
vb.push_back(SAuxObjVertex(v, Vec3(0.0f, 1.0f, 0.0f)));
|
|
}
|
|
|
|
// build faces
|
|
for (uint16 i(0); i < sections; ++i)
|
|
{
|
|
ib.push_back(vIdx);
|
|
ib.push_back(vIdx + 1 + i + 1);
|
|
ib.push_back(vIdx + 1 + i);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Functor to generate a sphere mesh. To be used with generalized CreateMesh function.
|
|
struct SSphereMeshCreateFunc
|
|
{
|
|
SSphereMeshCreateFunc(float radius, unsigned int rings, unsigned int sections)
|
|
: m_radius(radius)
|
|
, m_rings(rings)
|
|
, m_sections(sections)
|
|
{
|
|
}
|
|
|
|
void CreateMesh(AuxObjVertexBuffer& vb, AuxObjIndexBuffer& ib)
|
|
{
|
|
CreateSphere(vb, ib, m_radius, m_rings, m_sections);
|
|
}
|
|
|
|
float m_radius;
|
|
unsigned int m_rings;
|
|
unsigned int m_sections;
|
|
};
|
|
|
|
// Functor to generate a disk mesh. To be used with generalized CreateMesh function.
|
|
struct SDiskMeshCreateFunc
|
|
{
|
|
SDiskMeshCreateFunc(float radius, unsigned int rings)
|
|
: m_radius(radius)
|
|
, m_rings(rings)
|
|
{
|
|
}
|
|
|
|
void CreateMesh(AuxObjVertexBuffer& vb, AuxObjIndexBuffer& ib)
|
|
{
|
|
CreateDisk(vb, ib, m_radius, m_rings);
|
|
}
|
|
|
|
float m_radius;
|
|
unsigned int m_rings;
|
|
};
|
|
|
|
// Functor to generate a quad mesh. To be used with generalized CreateMesh function.
|
|
struct SQuadMeshCreateFunc
|
|
{
|
|
SQuadMeshCreateFunc(float width, float height)
|
|
: m_width(width)
|
|
, m_height(height)
|
|
{
|
|
}
|
|
|
|
void CreateMesh(AuxObjVertexBuffer& vb, AuxObjIndexBuffer& ib)
|
|
{
|
|
CreateQuad(vb, ib, m_width, m_height);
|
|
}
|
|
|
|
float m_width;
|
|
float m_height;
|
|
};
|
|
|
|
|
|
|
|
// Functor to generate a cone mesh. To be used with generalized CreateMesh function.
|
|
struct SConeMeshCreateFunc
|
|
{
|
|
SConeMeshCreateFunc(float radius, float height, unsigned int sections)
|
|
: m_radius(radius)
|
|
, m_height(height)
|
|
, m_sections(sections)
|
|
{
|
|
}
|
|
|
|
void CreateMesh(AuxObjVertexBuffer& vb, AuxObjIndexBuffer& ib)
|
|
{
|
|
CreateCone(vb, ib, m_radius, m_height, m_sections);
|
|
}
|
|
|
|
float m_radius;
|
|
float m_height;
|
|
unsigned int m_sections;
|
|
};
|
|
|
|
|
|
// Functor to generate a cylinder mesh. To be used with generalized CreateMesh function.
|
|
struct SCylinderMeshCreateFunc
|
|
{
|
|
SCylinderMeshCreateFunc(float radius, float height, unsigned int sections)
|
|
: m_radius(radius)
|
|
, m_height(height)
|
|
, m_sections(sections)
|
|
{
|
|
}
|
|
|
|
void CreateMesh(AuxObjVertexBuffer& vb, AuxObjIndexBuffer& ib)
|
|
{
|
|
CreateCylinder(vb, ib, m_radius, m_height, m_sections);
|
|
}
|
|
|
|
float m_radius;
|
|
float m_height;
|
|
unsigned int m_sections;
|
|
};
|
|
|
|
|
|
// Generalized CreateMesh function to create any mesh via passed-in functor.
|
|
// The functor needs to provide a CreateMesh function which accepts an
|
|
// AuxObjVertexBuffer and AuxObjIndexBuffer to stored the resulting mesh.
|
|
template< typename TMeshFunc >
|
|
HRESULT CRenderAuxGeomD3D::CreateMesh(SDrawObjMesh& mesh, TMeshFunc meshFunc)
|
|
{
|
|
// create mesh
|
|
std::vector< SAuxObjVertex > vb;
|
|
std::vector< uint16 > ib;
|
|
meshFunc.CreateMesh(vb, ib);
|
|
|
|
// create vertex buffer and copy data
|
|
HRESULT hr(S_OK);
|
|
D3D11_BUFFER_DESC BufDescV;
|
|
ZeroStruct(BufDescV);
|
|
BufDescV.ByteWidth = vb.size() * sizeof(SAuxObjVertex);
|
|
BufDescV.Usage = D3D11_USAGE_DEFAULT;
|
|
BufDescV.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
|
BufDescV.CPUAccessFlags = 0;
|
|
BufDescV.MiscFlags = 0;
|
|
|
|
D3D11_SUBRESOURCE_DATA InitData;
|
|
InitData.pSysMem = &vb[0];
|
|
InitData.SysMemPitch = 0;
|
|
InitData.SysMemSlicePitch = 0;
|
|
if (FAILED(hr = m_renderer.m_DevMan.CreateD3D11Buffer(&BufDescV, &InitData, &mesh.m_pVB, "AuxGeometryMesh")))
|
|
{
|
|
assert(SUCCEEDED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
D3D11_BUFFER_DESC BufDescI;
|
|
ZeroStruct(BufDescI);
|
|
BufDescI.ByteWidth = ib.size() * sizeof(uint16);
|
|
BufDescI.Usage = D3D11_USAGE_DEFAULT;
|
|
BufDescI.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
|
BufDescI.CPUAccessFlags = 0;
|
|
BufDescI.MiscFlags = 0;
|
|
|
|
InitData.pSysMem = &ib[0];
|
|
InitData.SysMemPitch = 0;
|
|
InitData.SysMemSlicePitch = 0;
|
|
if (FAILED(hr = m_renderer.m_DevMan.CreateD3D11Buffer(&BufDescI, &InitData, &mesh.m_pIB, "AuxGeometryMesh")))
|
|
{
|
|
assert(SUCCEEDED(hr));
|
|
return(hr);
|
|
}
|
|
|
|
// write mesh info
|
|
mesh.m_numVertices = vb.size();
|
|
mesh.m_numFaces = ib.size() / 3;
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT CRenderAuxGeomD3D::RestoreDeviceObjects()
|
|
{
|
|
HRESULT hr(S_OK);
|
|
|
|
// recreate vertex buffer
|
|
gcpRendD3D->m_DevMan.ReleaseD3D11Buffer(m_pAuxGeomVB);
|
|
m_pAuxGeomVB = nullptr;
|
|
|
|
D3D11_BUFFER_DESC BufDescV;
|
|
ZeroStruct(BufDescV);
|
|
BufDescV.ByteWidth = e_auxGeomVBSize * sizeof(SAuxVertex);
|
|
#if defined(CRY_USE_METAL)
|
|
//Direct access memory is faster on metal as it only needs one CPU->GPU copy whereas the
|
|
//dynamic memory (for vertex buffers) will do a CPU->GPU and then a GPU->GPU copy.
|
|
BufDescV.Usage = D3D11_USAGE_DIRECT_ACCESS;
|
|
#else
|
|
BufDescV.Usage = D3D11_USAGE_DYNAMIC;
|
|
#endif
|
|
BufDescV.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
|
BufDescV.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
BufDescV.MiscFlags = 0;
|
|
|
|
if (FAILED(hr = m_renderer.m_DevMan.CreateD3D11Buffer(&BufDescV, 0, &m_pAuxGeomVB, "AuxGeometry")))
|
|
{
|
|
assert(0);
|
|
return(hr);
|
|
}
|
|
|
|
// recreate index buffer
|
|
gcpRendD3D->m_DevMan.ReleaseD3D11Buffer(m_pAuxGeomIB);
|
|
m_pAuxGeomIB = nullptr;
|
|
|
|
D3D11_BUFFER_DESC BufDescI;
|
|
ZeroStruct(BufDescI);
|
|
BufDescI.ByteWidth = e_auxGeomIBSize * sizeof(uint16);
|
|
#if defined(CRY_USE_METAL)
|
|
//Direct access memory is faster on metal as it only needs one CPU->GPU copy whereas the
|
|
//dynamic memory (for index buffers) will do a CPU->GPU and then a GPU->GPU copy.
|
|
BufDescI.Usage = D3D11_USAGE_DIRECT_ACCESS;
|
|
#else
|
|
BufDescI.Usage = D3D11_USAGE_DYNAMIC;
|
|
#endif
|
|
BufDescI.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
|
BufDescI.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
BufDescI.MiscFlags = 0;
|
|
if (FAILED(hr = m_renderer.m_DevMan.CreateD3D11Buffer(&BufDescI, 0, &m_pAuxGeomIB, "AuxGeometry")))
|
|
{
|
|
assert(0);
|
|
return(hr);
|
|
}
|
|
|
|
// recreate aux objects
|
|
for (uint32 i(0); i < e_auxObjNumLOD; ++i)
|
|
{
|
|
m_sphereObj[ i ].Release();
|
|
if (FAILED(hr = CreateMesh(m_sphereObj[ i ], SSphereMeshCreateFunc(1.0f, 9 + 4 * i, 9 + 4 * i))))
|
|
{
|
|
return(hr);
|
|
}
|
|
|
|
m_diskObj[i].Release();
|
|
if (FAILED(hr = CreateMesh(m_diskObj[ i ], SDiskMeshCreateFunc(1.0f, 9 + 4 * i))))
|
|
{
|
|
return(hr);
|
|
}
|
|
|
|
m_quadObj[i].Release();
|
|
if (FAILED(hr = CreateMesh(m_quadObj[i], SQuadMeshCreateFunc(1.0f, 1.0f))))
|
|
{
|
|
return(hr);
|
|
}
|
|
|
|
m_coneObj[ i ].Release();
|
|
if (FAILED(hr = CreateMesh(m_coneObj[ i ], SConeMeshCreateFunc(1.0f, 1.0f, 10 + i * 6))))
|
|
{
|
|
return(hr);
|
|
}
|
|
|
|
m_cylinderObj[ i ].Release();
|
|
if (FAILED(hr = CreateMesh(m_cylinderObj[ i ], SCylinderMeshCreateFunc(1.0f, 1.0f, 10 + i * 6))))
|
|
{
|
|
return(hr);
|
|
}
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::DrawAuxPrimitives(CAuxGeomCB::AuxSortedPushBuffer::const_iterator itBegin, CAuxGeomCB::AuxSortedPushBuffer::const_iterator itEnd, const CAuxGeomCB::EPrimType& primType)
|
|
{
|
|
assert(CAuxGeomCB::e_PtList == primType || CAuxGeomCB::e_LineList == primType || CAuxGeomCB::e_TriList == primType);
|
|
|
|
HRESULT hr(S_OK);
|
|
|
|
// bind vertex and index streams and set vertex declaration
|
|
bool streamsBound = BindStreams(m_auxGeomPrimitiveVertexFormat, m_pAuxGeomVB, m_pAuxGeomIB);
|
|
|
|
// get aux vertex buffer
|
|
const CAuxGeomCB::AuxVertexBuffer& auxVertexBuffer(GetAuxVertexBuffer());
|
|
|
|
// determine flags for prim type
|
|
uint32 d3dNumPrimDivider;
|
|
eRenderPrimitiveType ePrimType;
|
|
|
|
DetermineAuxPrimitveFlags(d3dNumPrimDivider, ePrimType, primType);
|
|
|
|
// helpers for DP call
|
|
uint32 initialVBLockOffset(m_auxGeomSBM.m_curVBIndex);
|
|
uint32 numVerticesWrittenToVB(0);
|
|
|
|
m_renderer.FX_Commit();
|
|
|
|
// process each entry
|
|
for (CAuxGeomCB::AuxSortedPushBuffer::const_iterator it(itBegin); it != itEnd; ++it)
|
|
{
|
|
// get current push buffer entry
|
|
const CAuxGeomCB::SAuxPushBufferEntry* curPBEntry(*it);
|
|
|
|
// number of vertices to copy
|
|
uint32 verticesToCopy(curPBEntry->m_numVertices);
|
|
uint32 verticesCopied(0);
|
|
|
|
// stream vertex data
|
|
while (verticesToCopy > 0)
|
|
{
|
|
// number of vertices which fit into current vb
|
|
uint32 maxVerticesInThisBatch(e_auxGeomVBSize - m_auxGeomSBM.m_curVBIndex);
|
|
|
|
// round down to previous multiple of "d3dNumPrimDivider"
|
|
maxVerticesInThisBatch -= maxVerticesInThisBatch % d3dNumPrimDivider;
|
|
|
|
// still enough space to feed data in the current vb
|
|
if (maxVerticesInThisBatch > 0)
|
|
{
|
|
// compute amount of vertices to move in this batch
|
|
uint32 toCopy(verticesToCopy > maxVerticesInThisBatch ? maxVerticesInThisBatch : verticesToCopy);
|
|
|
|
// get pointer to vertex buffer
|
|
SAuxVertex* pVertices(0);
|
|
// determine lock flags
|
|
D3D11_MAP mapFlags(D3D11_MAP_WRITE_NO_OVERWRITE);
|
|
if (false != m_auxGeomSBM.m_discardVB)
|
|
{
|
|
m_auxGeomSBM.m_discardVB = false;
|
|
mapFlags = D3D11_MAP_WRITE_DISCARD;
|
|
}
|
|
|
|
D3D11_MAPPED_SUBRESOURCE mappedResource;
|
|
if (FAILED(hr = m_renderer.GetDeviceContext().Map(m_pAuxGeomVB, 0, mapFlags, 0, &mappedResource)))
|
|
{
|
|
assert(0);
|
|
iLog->Log("ERROR: CD3DRenderAuxGeom::DrawAuxPrimitives() - Vertex buffer could not be locked!");
|
|
return;
|
|
}
|
|
pVertices = (SAuxVertex*)mappedResource.pData;
|
|
pVertices += m_auxGeomSBM.m_curVBIndex;
|
|
|
|
// move vertex data
|
|
// cppcheck-suppress nullPointer
|
|
memcpy(pVertices, &auxVertexBuffer[ curPBEntry->m_vertexOffs + verticesCopied ], toCopy * sizeof(SAuxVertex));
|
|
|
|
// unlock vb
|
|
m_renderer.GetDeviceContext().Unmap(m_pAuxGeomVB, 0);
|
|
// update accumulators and buffer indices
|
|
verticesCopied += toCopy;
|
|
verticesToCopy -= toCopy;
|
|
|
|
m_auxGeomSBM.m_curVBIndex += toCopy;
|
|
numVerticesWrittenToVB += toCopy;
|
|
}
|
|
else
|
|
{
|
|
// not enough space in vb for (remainder of) current push buffer entry
|
|
if (numVerticesWrittenToVB > 0)
|
|
{
|
|
// commit batch
|
|
assert(0 == numVerticesWrittenToVB % d3dNumPrimDivider);
|
|
if (streamsBound)
|
|
{
|
|
m_renderer.FX_DrawPrimitive(ePrimType, initialVBLockOffset, numVerticesWrittenToVB);
|
|
}
|
|
}
|
|
|
|
// request a DISCARD lock of vb in the next run
|
|
m_auxGeomSBM.DiscardVB();
|
|
initialVBLockOffset = m_auxGeomSBM.m_curVBIndex;
|
|
numVerticesWrittenToVB = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (numVerticesWrittenToVB > 0)
|
|
{
|
|
// commit batch
|
|
assert(0 == numVerticesWrittenToVB % d3dNumPrimDivider);
|
|
|
|
if (streamsBound)
|
|
{
|
|
m_renderer.FX_DrawPrimitive(ePrimType, initialVBLockOffset, numVerticesWrittenToVB);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::DrawAuxIndexedPrimitives(CAuxGeomCB::AuxSortedPushBuffer::const_iterator itBegin, CAuxGeomCB::AuxSortedPushBuffer::const_iterator itEnd, const CAuxGeomCB::EPrimType& primType)
|
|
{
|
|
assert(CAuxGeomCB::e_LineListInd == primType || CAuxGeomCB::e_TriListInd == primType);
|
|
|
|
HRESULT hr(S_OK);
|
|
|
|
// bind vertex and index streams and set vertex declaration
|
|
bool streamsBound = BindStreams(eVF_P3F_C4B_T2F, m_pAuxGeomVB, m_pAuxGeomIB);
|
|
|
|
// get aux vertex and index buffer
|
|
const CAuxGeomCB::AuxVertexBuffer& auxVertexBuffer(GetAuxVertexBuffer());
|
|
const CAuxGeomCB::AuxIndexBuffer& auxIndexBuffer(GetAuxIndexBuffer());
|
|
|
|
// determine flags for prim type
|
|
uint32 d3dNumPrimDivider;
|
|
eRenderPrimitiveType ePrimType;
|
|
DetermineAuxPrimitveFlags(d3dNumPrimDivider, ePrimType, primType);
|
|
|
|
// helpers for DP call
|
|
uint32 initialVBLockOffset(m_auxGeomSBM.m_curVBIndex);
|
|
uint32 numVerticesWrittenToVB(0);
|
|
uint32 initialIBLockOffset(m_auxGeomSBM.m_curIBIndex);
|
|
uint32 numIndicesWrittenToIB(0);
|
|
|
|
m_renderer.FX_Commit();
|
|
|
|
// process each entry
|
|
for (CAuxGeomCB::AuxSortedPushBuffer::const_iterator it(itBegin); it != itEnd; )
|
|
{
|
|
// get current push buffer entry
|
|
const CAuxGeomCB::SAuxPushBufferEntry* curPBEntry(*it);
|
|
|
|
// process a push buffer entry if it can fit at all (otherwise silently skip it)
|
|
if (e_auxGeomVBSize >= curPBEntry->m_numVertices && e_auxGeomIBSize >= curPBEntry->m_numIndices)
|
|
{
|
|
// check if push buffer still fits into current buffer
|
|
if (e_auxGeomVBSize >= m_auxGeomSBM.m_curVBIndex + curPBEntry->m_numVertices && e_auxGeomIBSize >= m_auxGeomSBM.m_curIBIndex + curPBEntry->m_numIndices)
|
|
{
|
|
// determine lock vb flags
|
|
|
|
// get pointer to vertex buffer
|
|
SAuxVertex* pVertices(0);
|
|
D3D11_MAP mp (D3D11_MAP_WRITE_NO_OVERWRITE);
|
|
if (false != m_auxGeomSBM.m_discardVB)
|
|
{
|
|
m_auxGeomSBM.m_discardVB = false;
|
|
mp = D3D11_MAP_WRITE_DISCARD;
|
|
}
|
|
D3D11_MAPPED_SUBRESOURCE mappedResource;
|
|
if (FAILED(hr = m_renderer.GetDeviceContext().Map(m_pAuxGeomVB, 0, mp, 0, &mappedResource)))
|
|
{
|
|
assert(0);
|
|
iLog->Log("ERROR: CD3DRenderAuxGeom::DrawAuxIndexedPrimitives() - Vertex buffer could not be locked!");
|
|
return;
|
|
}
|
|
pVertices = (SAuxVertex*)mappedResource.pData;
|
|
pVertices += m_auxGeomSBM.m_curVBIndex;
|
|
|
|
// move vertex data of this entry
|
|
// cppcheck-suppress nullPointer
|
|
memcpy(pVertices, &auxVertexBuffer[ curPBEntry->m_vertexOffs ], curPBEntry->m_numVertices * sizeof(SAuxVertex));
|
|
|
|
// unlock vb
|
|
m_renderer.GetDeviceContext().Unmap(m_pAuxGeomVB, 0);
|
|
|
|
// get pointer to index buffer
|
|
uint16* pIndices(0);
|
|
mp = D3D11_MAP_WRITE_NO_OVERWRITE;
|
|
if (false != m_auxGeomSBM.m_discardIB)
|
|
{
|
|
m_auxGeomSBM.m_discardIB = false;
|
|
mp = D3D11_MAP_WRITE_DISCARD;
|
|
}
|
|
|
|
if (FAILED(hr = m_renderer.GetDeviceContext().Map(m_pAuxGeomIB, 0, mp, 0, &mappedResource)))
|
|
{
|
|
assert(0);
|
|
iLog->Log("ERROR: CD3DRenderAuxGeom::DrawAuxIndexedPrimitives() - Index buffer could not be locked!");
|
|
|
|
m_renderer.GetDeviceContext().Unmap(m_pAuxGeomVB, 0);
|
|
return;
|
|
}
|
|
pIndices = (uint16*)mappedResource.pData;
|
|
pIndices += m_auxGeomSBM.m_curIBIndex;
|
|
|
|
// move index data of this entry (modify indices to match VB insert location)
|
|
for (uint32 i(0); i < curPBEntry->m_numIndices; ++i)
|
|
{
|
|
// cppcheck-suppress nullPointer
|
|
pIndices[ i ] = numVerticesWrittenToVB + auxIndexBuffer[ curPBEntry->m_indexOffs + i ];
|
|
}
|
|
|
|
// unlock ib
|
|
m_renderer.GetDeviceContext().Unmap(m_pAuxGeomIB, 0);
|
|
|
|
// update buffer indices
|
|
m_auxGeomSBM.m_curVBIndex += curPBEntry->m_numVertices;
|
|
m_auxGeomSBM.m_curIBIndex += curPBEntry->m_numIndices;
|
|
|
|
numVerticesWrittenToVB += curPBEntry->m_numVertices;
|
|
numIndicesWrittenToIB += curPBEntry->m_numIndices;
|
|
|
|
// advance to next push puffer entry
|
|
++it;
|
|
}
|
|
else
|
|
{
|
|
// push buffer entry currently doesn't fit, will be processed in the next iteration when buffers got flushed
|
|
if (numVerticesWrittenToVB > 0 && numIndicesWrittenToIB > 0)
|
|
{
|
|
// commit batch
|
|
assert(0 == numIndicesWrittenToIB % d3dNumPrimDivider);
|
|
if (streamsBound)
|
|
{
|
|
m_renderer.FX_DrawIndexedPrimitive(ePrimType, initialVBLockOffset, 0, numVerticesWrittenToVB, initialIBLockOffset, numIndicesWrittenToIB);
|
|
}
|
|
}
|
|
|
|
// request a DISCARD lock / don't advance iterator!
|
|
m_auxGeomSBM.DiscardVB();
|
|
initialVBLockOffset = m_auxGeomSBM.m_curVBIndex;
|
|
numVerticesWrittenToVB = 0;
|
|
|
|
m_auxGeomSBM.DiscardIB();
|
|
initialIBLockOffset = m_auxGeomSBM.m_curIBIndex;
|
|
numIndicesWrittenToIB = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// push buffer entry too big for dedicated vb/ib buffer
|
|
// advance to next push puffer entry
|
|
assert(0);
|
|
iLog->Log("ERROR: CD3DRenderAuxGeom::DrawAuxIndexedPrimitives() - Auxiliary geometry too big to render!");
|
|
++it;
|
|
}
|
|
}
|
|
|
|
if (numVerticesWrittenToVB > 0 && numIndicesWrittenToIB > 0)
|
|
{
|
|
// commit batch
|
|
assert(0 == numIndicesWrittenToIB % d3dNumPrimDivider);
|
|
if (streamsBound)
|
|
{
|
|
m_renderer.FX_DrawIndexedPrimitive(ePrimType, initialVBLockOffset, 0, numVerticesWrittenToVB, initialIBLockOffset, numIndicesWrittenToIB);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::DrawAuxObjects(CAuxGeomCB::AuxSortedPushBuffer::const_iterator itBegin, CAuxGeomCB::AuxSortedPushBuffer::const_iterator itEnd)
|
|
{
|
|
CAuxGeomCB::EAuxDrawObjType objType(CAuxGeomCB::GetAuxObjType((*itBegin)->m_renderFlags));
|
|
|
|
// get draw params buffer
|
|
const CAuxGeomCB::AuxDrawObjParamBuffer& auxDrawObjParamBuffer(GetAuxDrawObjParamBuffer());
|
|
|
|
// process each entry
|
|
for (CAuxGeomCB::AuxSortedPushBuffer::const_iterator it(itBegin); it != itEnd; ++it)
|
|
{
|
|
// get current push buffer entry
|
|
const CAuxGeomCB::SAuxPushBufferEntry* curPBEntry(*it);
|
|
|
|
// assert than all objects in this batch are of same type
|
|
assert(CAuxGeomCB::GetAuxObjType(curPBEntry->m_renderFlags) == objType);
|
|
|
|
uint32 drawParamOffs(0);
|
|
if (curPBEntry->GetDrawParamOffs(drawParamOffs))
|
|
{
|
|
// get draw params
|
|
const CAuxGeomCB::SAuxDrawObjParams& drawParams(auxDrawObjParamBuffer[ drawParamOffs ]);
|
|
|
|
// Prepare d3d world space matrix in draw param structure
|
|
// Attention: in d3d terms matWorld is actually matWorld^T
|
|
Matrix44A matWorld;
|
|
matWorld.SetIdentity();
|
|
memcpy(&matWorld, &drawParams.m_matWorld, sizeof(drawParams.m_matWorld));
|
|
|
|
// set transformation matrices
|
|
static CCryNameR matWorldViewProjName("matWorldViewProj");
|
|
if (m_curDrawInFrontMode == e_DrawInFrontOn)
|
|
{
|
|
Matrix44A matScale(Matrix44A(Matrix34::CreateScale(Vec3(0.999f, 0.999f, 0.999f))));
|
|
|
|
Matrix44A matWorldViewScaleProjT;
|
|
matWorldViewScaleProjT = (GetCurrentView() * matScale);
|
|
matWorldViewScaleProjT = matWorldViewScaleProjT * GetCurrentProj();
|
|
|
|
matWorldViewScaleProjT = matWorldViewScaleProjT.GetTransposed();
|
|
matWorldViewScaleProjT = matWorldViewScaleProjT * matWorld;
|
|
m_pAuxGeomShader->FXSetVSFloat(matWorldViewProjName, alias_cast<Vec4*>(&matWorldViewScaleProjT), 4);
|
|
}
|
|
else
|
|
{
|
|
Matrix44A matWorldViewProjT;
|
|
matWorldViewProjT = m_matrices.m_pCurTransMat->GetTransposed();
|
|
matWorldViewProjT = matWorldViewProjT * matWorld;
|
|
m_pAuxGeomShader->FXSetVSFloat(matWorldViewProjName, alias_cast<Vec4*>(&matWorldViewProjT), 4);
|
|
}
|
|
|
|
// set color
|
|
ColorF col(drawParams.m_color);
|
|
Vec4 colVec(col.b, col.g, col.r, col.a); // need to flip r/b as drawParams.m_color was originally argb
|
|
static CCryNameR auxGeomObjColorName("auxGeomObjColor");
|
|
m_pAuxGeomShader->FXSetVSFloat(auxGeomObjColorName, &colVec, 1);
|
|
|
|
// set shading flag
|
|
Vec4 shadingVec(drawParams.m_shaded ? 0.4f : 0, drawParams.m_shaded ? 0.6f : 1, 0, 0);
|
|
static CCryNameR auxGeomObjShadingName("auxGeomObjShading");
|
|
m_pAuxGeomShader->FXSetVSFloat(auxGeomObjShadingName, &shadingVec, 1);
|
|
|
|
// set light vector (rotate back into local space)
|
|
Matrix33 matWorldInv(drawParams.m_matWorldRotation.GetInverted());
|
|
Vec3 lightLocalSpace(matWorldInv * Vec3(0.5773f, 0.5773f, 0.5773f));
|
|
|
|
// normalize light vector (matWorld could contain non-uniform scaling)
|
|
lightLocalSpace.Normalize();
|
|
Vec4 lightVec(lightLocalSpace.x, lightLocalSpace.y, lightLocalSpace.z, 0.0f);
|
|
static CCryNameR globalLightLocalName("globalLightLocal");
|
|
m_pAuxGeomShader->FXSetVSFloat(globalLightLocalName, &lightVec, 1);
|
|
|
|
// LOD calculation
|
|
Matrix44A matWorldT;
|
|
matWorldT = matWorld.GetTransposed();
|
|
|
|
Vec4 objCenterWorld;
|
|
Vec3 nullVec(0.0f, 0.0f, 0.0f);
|
|
mathVec3TransformF(&objCenterWorld, &nullVec, &matWorldT);
|
|
Vec4 objOuterRightWorld(objCenterWorld + (Vec4(GetCurrentView().m00, GetCurrentView().m10, GetCurrentView().m20, 0.0f) * drawParams.m_size));
|
|
|
|
Vec4 v0, v1;
|
|
|
|
Vec3 objCenterWorldVec(objCenterWorld.x, objCenterWorld.y, objCenterWorld.z);
|
|
Vec3 objOuterRightWorldVec(objOuterRightWorld.x, objOuterRightWorld.y, objOuterRightWorld.z);
|
|
mathVec3TransformF(&v0, &objCenterWorldVec, m_matrices.m_pCurTransMat);
|
|
mathVec3TransformF(&v1, &objOuterRightWorldVec, m_matrices.m_pCurTransMat);
|
|
|
|
float scale;
|
|
assert(fabs(v0.w - v0.w) < 1e-4);
|
|
if (fabs(v0.w) < 1e-2)
|
|
{
|
|
scale = 0.5f;
|
|
}
|
|
else
|
|
{
|
|
scale = ((v1.x - v0.x) / v0.w) * (float) max(m_wndXRes, m_wndYRes) / 500.0f;
|
|
}
|
|
|
|
// map scale to detail level
|
|
uint32 lodLevel((uint32) ((scale / 0.5f) * (e_auxObjNumLOD - 1)));
|
|
if (lodLevel >= e_auxObjNumLOD)
|
|
{
|
|
lodLevel = e_auxObjNumLOD - 1;
|
|
}
|
|
|
|
// get appropriate mesh
|
|
assert(lodLevel >= 0 && lodLevel < e_auxObjNumLOD);
|
|
SDrawObjMesh* pMesh(0);
|
|
switch (objType)
|
|
{
|
|
case CAuxGeomCB::eDOT_Sphere:
|
|
default:
|
|
{
|
|
pMesh = &m_sphereObj[ lodLevel ];
|
|
break;
|
|
}
|
|
case CAuxGeomCB::eDOT_Disk:
|
|
{
|
|
pMesh = &m_diskObj[ lodLevel ];
|
|
break;
|
|
}
|
|
case CAuxGeomCB::eDOT_Quad:
|
|
{
|
|
pMesh = &m_quadObj[lodLevel];
|
|
break;
|
|
}
|
|
case CAuxGeomCB::eDOT_Cone:
|
|
{
|
|
pMesh = &m_coneObj[ lodLevel ];
|
|
break;
|
|
}
|
|
case CAuxGeomCB::eDOT_Cylinder:
|
|
{
|
|
pMesh = &m_cylinderObj[ lodLevel ];
|
|
break;
|
|
}
|
|
}
|
|
assert(0 != pMesh);
|
|
|
|
// bind vertex and index streams and set vertex declaration
|
|
if (BindStreams(m_auxGeomObjectVertexFormat, pMesh->m_pVB, pMesh->m_pIB))
|
|
{
|
|
m_renderer.FX_Commit();
|
|
|
|
// draw mesh
|
|
m_renderer.FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, pMesh->m_numVertices, 0, pMesh->m_numFaces * 3);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(0); // GetDrawParamOffs( ... ) failed -- corrupt data in push buffer?
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline Vec3 IntersectLinePlane(const Vec3& o, const Vec3& d, const Plane& p, float& t)
|
|
{
|
|
t = -((p.n | o) + (p.d + c_clipThres)) / (p.n | d);
|
|
return(o + d * t);
|
|
}
|
|
|
|
// maps floating point channels (0.f to 1.f range) to DWORD
|
|
#define DWORD_COLORVALUE(r, g, b, a) \
|
|
DWORD( \
|
|
(((DWORD)((a) * 255.f) & 0xff) << 24) | \
|
|
(((DWORD)((r) * 255.f) & 0xff) << 16) | \
|
|
(((DWORD)((g) * 255.f) & 0xff) << 8) | \
|
|
(((DWORD)((b) * 255.f) & 0xff) << 0))
|
|
|
|
static inline DWORD ClipColor(const DWORD& c0, const DWORD& c1, float t)
|
|
{
|
|
// convert D3D DWORD color storage (ARGB) to custom ColorF storage (ColorB uses ABGR!)
|
|
const float f = 1.0f / 255.0f;
|
|
ColorF v0(
|
|
f * (float)(unsigned char)(c0 >> 16),
|
|
f * (float)(unsigned char)(c0 >> 8),
|
|
f * (float)(unsigned char)(c0 >> 0),
|
|
f * (float)(unsigned char)(c0 >> 24));
|
|
ColorF v1(
|
|
f * (float)(unsigned char)(c1 >> 16),
|
|
f * (float)(unsigned char)(c1 >> 8),
|
|
f * (float)(unsigned char)(c1 >> 0),
|
|
f * (float)(unsigned char)(c1 >> 24));
|
|
ColorF vRes(v0 + (v1 - v0) * t);
|
|
return(DWORD_COLORVALUE(vRes.r, vRes.g, vRes.b, vRes.a));
|
|
}
|
|
|
|
static bool ClipLine(Vec3* v, DWORD* c)
|
|
{
|
|
// get near plane to perform clipping
|
|
Plane nearPlane(*gRenDev->GetCamera().GetFrustumPlane(FR_PLANE_NEAR));
|
|
|
|
// get clipping flags
|
|
bool bV0Behind(-((nearPlane.n | v[ 0 ]) + nearPlane.d) < c_clipThres);
|
|
bool bV1Behind(-((nearPlane.n | v[ 1 ]) + nearPlane.d) < c_clipThres);
|
|
|
|
// proceed only if both are not behind near clipping plane
|
|
if (false == bV0Behind || false == bV1Behind)
|
|
{
|
|
if (false == bV0Behind && false == bV1Behind)
|
|
{
|
|
// no clipping needed
|
|
return(true);
|
|
}
|
|
|
|
// define line to be clipped
|
|
Vec3 p(v[ 0 ]);
|
|
Vec3 d(v[ 1 ] - v[ 0 ]);
|
|
|
|
// get clipped position
|
|
float t;
|
|
v[ 0 ] = (false == bV0Behind) ? v[ 0 ] : IntersectLinePlane(p, d, nearPlane, t);
|
|
v[ 1 ] = (false == bV1Behind) ? v[ 1 ] : IntersectLinePlane(p, d, nearPlane, t);
|
|
|
|
// get clipped colors
|
|
c[ 0 ] = (false == bV0Behind) ? c[ 0 ] : ClipColor(c[ 0 ], c[ 1 ], t);
|
|
c[ 1 ] = (false == bV1Behind) ? c[ 1 ] : ClipColor(c[ 0 ], c[ 1 ], t);
|
|
|
|
return(true);
|
|
}
|
|
else
|
|
{
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
|
|
static float ComputeConstantScale(const Vec3& v, const Matrix44A& matView, const Matrix44A& matProj, const uint32 wndXRes)
|
|
{
|
|
Vec4 vCam0;
|
|
mathVec3TransformF(&vCam0, &v, &matView);
|
|
|
|
Vec4 vCam1(vCam0);
|
|
vCam1.x += 1.0f;
|
|
|
|
const float a = vCam0.y * matProj.m10 + vCam0.z * matProj.m20 + matProj.m30;
|
|
const float b = vCam0.y * matProj.m13 + vCam0.z * matProj.m23 + matProj.m33;
|
|
|
|
float c0((vCam0.x * matProj.m00 + a) / (vCam0.x * matProj.m03 + b));
|
|
float c1((vCam1.x * matProj.m00 + a) / (vCam1.x * matProj.m03 + b));
|
|
|
|
float s = (float)wndXRes * (c1 - c0);
|
|
|
|
const float epsilon = 0.001f;
|
|
return (fabsf(s) >= epsilon) ? 1.0f / s : 1.0f / epsilon;
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::PrepareThickLines3D(CAuxGeomCB::AuxSortedPushBuffer::const_iterator itBegin, CAuxGeomCB::AuxSortedPushBuffer::const_iterator itEnd)
|
|
{
|
|
const CAuxGeomCB::AuxVertexBuffer& auxVertexBuffer(GetAuxVertexBuffer());
|
|
|
|
// process each entry
|
|
for (CAuxGeomCB::AuxSortedPushBuffer::const_iterator it(itBegin); it != itEnd; ++it)
|
|
{
|
|
// get current push buffer entry
|
|
const CAuxGeomCB::SAuxPushBufferEntry* curPBEntry(*it);
|
|
|
|
uint32 offset(curPBEntry->m_vertexOffs);
|
|
for (uint32 i(0); i < curPBEntry->m_numVertices / 6; ++i, offset += 6)
|
|
{
|
|
// get line vertices and thickness parameter
|
|
const float* aTmp0 = (const float*) &(auxVertexBuffer[ offset + 0 ].xyz.x);
|
|
const float* aTmp1 = (const float*) &(auxVertexBuffer[ offset + 1 ].xyz.x);
|
|
const Vec3 v[ 2 ] =
|
|
{
|
|
Vec3(aTmp0[0], aTmp0[1], aTmp0[2]),
|
|
Vec3(aTmp1[0], aTmp1[1], aTmp1[2])
|
|
};
|
|
DWORD col[ 2 ] =
|
|
{
|
|
auxVertexBuffer[ offset + 0 ].color.dcolor,
|
|
auxVertexBuffer[ offset + 1 ].color.dcolor
|
|
};
|
|
float thickness(auxVertexBuffer[ offset + 2 ].xyz.x);
|
|
|
|
bool skipLine(false);
|
|
Vec4 vf[ 4 ];
|
|
|
|
if (false == IsOrthoMode()) // regular, 3d projected geometry
|
|
{
|
|
skipLine = !ClipLine((Vec3*)v, col);
|
|
if (false == skipLine)
|
|
{
|
|
// compute depth corrected thickness of line end points
|
|
float thicknessV0(0.5f * thickness * ComputeConstantScale(v[ 0 ], GetCurrentView(), GetCurrentProj(), m_wndXRes));
|
|
float thicknessV1(0.5f * thickness * ComputeConstantScale(v[ 1 ], GetCurrentView(), GetCurrentProj(), m_wndXRes));
|
|
|
|
// compute camera space line delta
|
|
Vec4 vt[ 2 ];
|
|
mathVec3TransformF(&vt[ 0 ], &v[ 0 ], &GetCurrentView());
|
|
mathVec3TransformF(&vt[ 1 ], &v[ 1 ], &GetCurrentView());
|
|
vt[0].z = (float) fsel(-vt[0].z - c_clipThres, vt[0].z, -c_clipThres);
|
|
vt[1].z = (float) fsel(-vt[1].z - c_clipThres, vt[1].z, -c_clipThres);
|
|
Vec4 tmp(vt[ 1 ] / vt[ 1 ].z - vt[ 0 ] / vt[ 0 ].z);
|
|
Vec2 delta(tmp.x, tmp.y);
|
|
|
|
// create screen space normal of line delta
|
|
Vec2 normalVec(-delta.y, delta.x);
|
|
mathVec2NormalizeF(&normalVec, &normalVec);
|
|
Vec2 normal(normalVec.x, normalVec.y);
|
|
|
|
Vec2 n[ 2 ];
|
|
n[ 0 ] = normal * thicknessV0;
|
|
n[ 1 ] = normal * thicknessV1;
|
|
|
|
// compute final world space vertices of thick line
|
|
Vec4 vertices[4] =
|
|
{
|
|
Vec4(vt[ 0 ].x + n[ 0 ].x, vt[ 0 ].y + n[ 0 ].y, vt[ 0 ].z, vt[ 0 ].w),
|
|
Vec4(vt[ 1 ].x + n[ 1 ].x, vt[ 1 ].y + n[ 1 ].y, vt[ 1 ].z, vt[ 1 ].w),
|
|
Vec4(vt[ 1 ].x - n[ 1 ].x, vt[ 1 ].y - n[ 1 ].y, vt[ 1 ].z, vt[ 1 ].w),
|
|
Vec4(vt[ 0 ].x - n[ 0 ].x, vt[ 0 ].y - n[ 0 ].y, vt[ 0 ].z, vt[ 0 ].w)
|
|
};
|
|
mathVec4TransformF(&vf[ 0 ], &vertices[0], &GetCurrentViewInv());
|
|
mathVec4TransformF(&vf[ 1 ], &vertices[1], &GetCurrentViewInv());
|
|
mathVec4TransformF(&vf[ 2 ], &vertices[2], &GetCurrentViewInv());
|
|
mathVec4TransformF(&vf[ 3 ], &vertices[3], &GetCurrentViewInv());
|
|
}
|
|
}
|
|
else // orthogonal projected geometry
|
|
{
|
|
// compute depth corrected thickness of line end points
|
|
float thicknessV0(0.5f * thickness * ComputeConstantScale(v[ 0 ], GetCurrentView(), GetCurrentProj(), m_wndXRes));
|
|
float thicknessV1(0.5f * thickness * ComputeConstantScale(v[ 1 ], GetCurrentView(), GetCurrentProj(), m_wndXRes));
|
|
|
|
// compute line delta
|
|
Vec2 delta(v[ 1 ] - v[ 0 ]);
|
|
|
|
// create normal of line delta
|
|
Vec2 normalVec(-delta.y, delta.x);
|
|
mathVec2NormalizeF(&normalVec, &normalVec);
|
|
Vec2 normal(normalVec.x, normalVec.y);
|
|
|
|
Vec2 n[ 2 ];
|
|
n[ 0 ] = normal * thicknessV0 * 2.0f;
|
|
n[ 1 ] = normal * thicknessV1 * 2.0f;
|
|
|
|
// compute final world space vertices of thick line
|
|
vf[ 0 ] = Vec4(v[ 0 ].x + n[ 0 ].x, v[ 0 ].y + n[ 0 ].y, v[ 0 ].z, 1.0f);
|
|
vf[ 1 ] = Vec4(v[ 1 ].x + n[ 1 ].x, v[ 1 ].y + n[ 1 ].y, v[ 1 ].z, 1.0f);
|
|
vf[ 2 ] = Vec4(v[ 1 ].x - n[ 1 ].x, v[ 1 ].y - n[ 1 ].y, v[ 1 ].z, 1.0f);
|
|
vf[ 3 ] = Vec4(v[ 0 ].x - n[ 0 ].x, v[ 0 ].y - n[ 0 ].y, v[ 0 ].z, 1.0f);
|
|
}
|
|
|
|
SAuxVertex* pVertices(const_cast<SAuxVertex*>(&auxVertexBuffer[ offset ]));
|
|
if (false == skipLine)
|
|
{
|
|
// copy data to vertex buffer
|
|
pVertices[ 0 ].xyz = Vec3(vf[ 0 ].x, vf[ 0 ].y, vf[ 0 ].z);
|
|
pVertices[ 0 ].color.dcolor = col[ 0 ];
|
|
pVertices[ 1 ].xyz = Vec3(vf[ 1 ].x, vf[ 1 ].y, vf[ 1 ].z);
|
|
pVertices[ 1 ].color.dcolor = col[ 1 ];
|
|
pVertices[ 2 ].xyz = Vec3(vf[ 2 ].x, vf[ 2 ].y, vf[ 2 ].z);
|
|
pVertices[ 2 ].color.dcolor = col[ 1 ];
|
|
pVertices[ 3 ].xyz = Vec3(vf[ 0 ].x, vf[ 0 ].y, vf[ 0 ].z);
|
|
pVertices[ 3 ].color.dcolor = col[ 0 ];
|
|
pVertices[ 4 ].xyz = Vec3(vf[ 2 ].x, vf[ 2 ].y, vf[ 2 ].z);
|
|
pVertices[ 4 ].color.dcolor = col[ 1 ];
|
|
pVertices[ 5 ].xyz = Vec3(vf[ 3 ].x, vf[ 3 ].y, vf[ 3 ].z);
|
|
pVertices[ 5 ].color.dcolor = col[ 0 ];
|
|
}
|
|
else
|
|
{
|
|
// invalidate parameter data of thick line stored in vertex buffer
|
|
// (generates two black degenerated triangles at (0,0,0))
|
|
memset(pVertices, 0, sizeof(SAuxVertex) * 6);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::PrepareThickLines2D(CAuxGeomCB::AuxSortedPushBuffer::const_iterator itBegin, CAuxGeomCB::AuxSortedPushBuffer::const_iterator itEnd)
|
|
{
|
|
const CAuxGeomCB::AuxVertexBuffer& auxVertexBuffer(GetAuxVertexBuffer());
|
|
|
|
// process each entry
|
|
for (CAuxGeomCB::AuxSortedPushBuffer::const_iterator it(itBegin); it != itEnd; ++it)
|
|
{
|
|
// get current push buffer entry
|
|
const CAuxGeomCB::SAuxPushBufferEntry* curPBEntry(*it);
|
|
|
|
uint32 offset(curPBEntry->m_vertexOffs);
|
|
for (uint32 i(0); i < curPBEntry->m_numVertices / 6; ++i, offset += 6)
|
|
{
|
|
// get line vertices and thickness parameter
|
|
const float* aTmp0 = (const float*) &(auxVertexBuffer[ offset + 0 ].xyz.x);
|
|
const float* aTmp1 = (const float*) &(auxVertexBuffer[ offset + 1 ].xyz.x);
|
|
const Vec3 v[ 2 ] =
|
|
{
|
|
Vec3(aTmp0[0], aTmp0[1], aTmp0[2]),
|
|
Vec3(aTmp1[0], aTmp1[1], aTmp1[2])
|
|
};
|
|
const DWORD col[ 2 ] =
|
|
{
|
|
auxVertexBuffer[ offset + 0 ].color.dcolor,
|
|
auxVertexBuffer[ offset + 1 ].color.dcolor
|
|
};
|
|
float thickness(auxVertexBuffer[ offset + 2 ].xyz.x);
|
|
|
|
// get line delta and aspect ratio corrected normal
|
|
Vec3 delta(v[ 1 ] - v[ 0 ]);
|
|
Vec3 normalVec(-delta.y * m_aspectInv, delta.x * m_aspect, 0.0f);
|
|
|
|
// normalize and scale to line thickness
|
|
mathVec3NormalizeF(&normalVec, &normalVec);
|
|
Vec3 normal(normalVec.x, normalVec.y, normalVec.z);
|
|
normal *= thickness * 0.001f;
|
|
|
|
// compute final 2D vertices of thick line in normalized device space
|
|
Vec3 vf[ 4 ];
|
|
vf[ 0 ] = v[ 0 ] + normal;
|
|
vf[ 1 ] = v[ 1 ] + normal;
|
|
vf[ 2 ] = v[ 1 ] - normal;
|
|
vf[ 3 ] = v[ 0 ] - normal;
|
|
|
|
// copy data to vertex buffer
|
|
SAuxVertex* pVertices(const_cast<SAuxVertex*>(&auxVertexBuffer[ offset ]));
|
|
pVertices[ 0 ].xyz = Vec3(vf[ 0 ].x, vf[ 0 ].y, vf[ 0 ].z);
|
|
pVertices[ 0 ].color.dcolor = col[ 0 ];
|
|
pVertices[ 1 ].xyz = Vec3(vf[ 1 ].x, vf[ 1 ].y, vf[ 1 ].z);
|
|
pVertices[ 1 ].color.dcolor = col[ 1 ];
|
|
pVertices[ 2 ].xyz = Vec3(vf[ 2 ].x, vf[ 2 ].y, vf[ 2 ].z);
|
|
pVertices[ 2 ].color.dcolor = col[ 1 ];
|
|
pVertices[ 3 ].xyz = Vec3(vf[ 0 ].x, vf[ 0 ].y, vf[ 0 ].z);
|
|
pVertices[ 3 ].color.dcolor = col[ 0 ];
|
|
pVertices[ 4 ].xyz = Vec3(vf[ 2 ].x, vf[ 2 ].y, vf[ 2 ].z);
|
|
pVertices[ 4 ].color.dcolor = col[ 1 ];
|
|
pVertices[ 5 ].xyz = Vec3(vf[ 3 ].x, vf[ 3 ].y, vf[ 3 ].z);
|
|
pVertices[ 5 ].color.dcolor = col[ 0 ];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::PrepareRendering()
|
|
{
|
|
// update transformation matrices
|
|
m_matrices.UpdateMatrices(m_renderer);
|
|
|
|
// get current window resultion and update aspect ratios
|
|
m_wndXRes = m_renderer.GetWidth();
|
|
m_wndYRes = m_renderer.GetHeight();
|
|
|
|
m_aspect = 1.0f;
|
|
m_aspectInv = 1.0f;
|
|
if (m_wndXRes > 0 && m_wndYRes > 0)
|
|
{
|
|
m_aspect = (float) m_wndXRes / (float) m_wndYRes;
|
|
m_aspectInv = 1.0f / m_aspect;
|
|
}
|
|
|
|
// reset DrawInFront mode
|
|
m_curDrawInFrontMode = e_DrawInFrontOff;
|
|
|
|
// reset stream buffer manager
|
|
m_auxGeomSBM.Reset();
|
|
|
|
// reset current VB/IB
|
|
m_pCurVB = 0;
|
|
m_pCurIB = 0;
|
|
|
|
// reset current prim type
|
|
m_curPrimType = CAuxGeomCB::e_PrimTypeInvalid;
|
|
|
|
// set vertex format
|
|
//m_renderer.m_RP.m_CurVFormat = m_auxGeomVertexFormat;
|
|
}
|
|
|
|
|
|
bool CRenderAuxGeomD3D::BindStreams(const AZ::Vertex::Format& newVertexFormat, D3DBuffer* pNewVB, D3DBuffer* pNewIB)
|
|
{
|
|
// set vertex declaration
|
|
if (FAILED(m_renderer.FX_SetVertexDeclaration(0, newVertexFormat)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// bind streams
|
|
HRESULT hr = S_OK;
|
|
if (m_pCurVB != pNewVB)
|
|
{
|
|
hr = m_renderer.FX_SetVStream(0, pNewVB, 0, newVertexFormat.GetStride());
|
|
m_pCurVB = pNewVB;
|
|
}
|
|
if (m_pCurIB != pNewIB)
|
|
{
|
|
hr = m_renderer.FX_SetIStream(pNewIB, 0, Index16);
|
|
m_pCurIB = pNewIB;
|
|
}
|
|
|
|
return SUCCEEDED(hr);
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::SetShader(const SAuxGeomRenderFlags& renderFlags)
|
|
{
|
|
if (0 == m_pAuxGeomShader)
|
|
{
|
|
// allow invalid file access for this shader because it shouldn't be used in the final build anyway
|
|
CDebugAllowFileAccess ignoreInvalidFileAccess;
|
|
m_pAuxGeomShader = m_renderer.m_cEF.mfForName("AuxGeom", EF_SYSTEM);
|
|
assert(0 != m_pAuxGeomShader);
|
|
}
|
|
|
|
if (0 != m_pAuxGeomShader)
|
|
{
|
|
bool dirty(0 != (m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_PersFlags & RBPF_FP_DIRTY));
|
|
if (false != dirty)
|
|
{
|
|
// NOTE: dirty flags are either set when setting EF_ColorOp in AdjustRenderStates
|
|
m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_PersFlags &= ~RBPF_FP_DIRTY;
|
|
m_renderer.m_RP.m_pCurObject = m_renderer.m_RP.m_pIdendityRenderObject;
|
|
m_renderer.m_RP.m_FlagsShader_LT = m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_eCurColorOp | (m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_eCurAlphaOp << 8) |
|
|
(m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_eCurColorArg << 16) | (m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_eCurAlphaArg << 24);
|
|
}
|
|
|
|
EAuxGeomPublicRenderflags_DrawInFrontMode newDrawInFrontMode(renderFlags.GetDrawInFrontMode());
|
|
CAuxGeomCB::EPrimType newPrimType(CAuxGeomCB::GetPrimType(renderFlags));
|
|
|
|
if (false != dirty || m_pAuxGeomShader != m_renderer.m_RP.m_pShader || m_curDrawInFrontMode != newDrawInFrontMode || m_curPrimType != newPrimType)
|
|
{
|
|
if (CAuxGeomCB::e_Obj != newPrimType)
|
|
{
|
|
static CCryNameTSCRC techName("AuxGeometry");
|
|
m_pAuxGeomShader->FXSetTechnique(techName);
|
|
m_pAuxGeomShader->FXBegin(&m_renderer.m_RP.m_nNumRendPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
|
|
m_pAuxGeomShader->FXBeginPass(0);
|
|
m_renderer.m_RP.m_CurVFormat = m_auxGeomPrimitiveVertexFormat;
|
|
|
|
static CCryNameR matViewProjName("matViewProj");
|
|
if (e_DrawInFrontOn == renderFlags.GetDrawInFrontMode() && e_Mode3D == renderFlags.GetMode2D3DFlag())
|
|
{
|
|
Matrix44A matScale(Matrix44(Matrix34::CreateScale(Vec3(0.999f, 0.999f, 0.999f))));
|
|
|
|
Matrix44A matViewScaleProjT;
|
|
matViewScaleProjT = GetCurrentView() * matScale;
|
|
matViewScaleProjT = matViewScaleProjT * GetCurrentProj();
|
|
matViewScaleProjT = matViewScaleProjT.GetTransposed();
|
|
m_pAuxGeomShader->FXSetVSFloat(matViewProjName, alias_cast<Vec4*>(&matViewScaleProjT), 4);
|
|
m_curDrawInFrontMode = e_DrawInFrontOn;
|
|
}
|
|
else
|
|
{
|
|
Matrix44A matViewProjT = m_matrices.m_pCurTransMat->GetTransposed();
|
|
m_pAuxGeomShader->FXSetVSFloat(matViewProjName, alias_cast<Vec4*>(&matViewProjT), 4);
|
|
m_curDrawInFrontMode = e_DrawInFrontOff;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static CCryNameTSCRC techName("AuxGeometryObj");
|
|
m_pAuxGeomShader->FXSetTechnique(techName);
|
|
m_pAuxGeomShader->FXBegin(&m_renderer.m_RP.m_nNumRendPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
|
|
m_pAuxGeomShader->FXBeginPass(0);
|
|
m_renderer.m_RP.m_CurVFormat = m_auxGeomObjectVertexFormat;
|
|
|
|
if (e_DrawInFrontOn == renderFlags.GetDrawInFrontMode() && e_Mode3D == renderFlags.GetMode2D3DFlag())
|
|
{
|
|
m_curDrawInFrontMode = e_DrawInFrontOn;
|
|
}
|
|
else
|
|
{
|
|
m_curDrawInFrontMode = e_DrawInFrontOff;
|
|
}
|
|
}
|
|
m_curPrimType = newPrimType;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_renderer.FX_SetFPMode();
|
|
}
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::AdjustRenderStates(const SAuxGeomRenderFlags& renderFlags)
|
|
{
|
|
// init current render states mask
|
|
uint32 curRenderStates(0);
|
|
|
|
// mode 2D/3D -- set new transformation matrix
|
|
const Matrix44A* pNewTransMat(&GetCurrentTrans3D());
|
|
if (e_Mode2D == renderFlags.GetMode2D3DFlag())
|
|
{
|
|
pNewTransMat = &GetCurrentTrans2D();
|
|
}
|
|
if (m_matrices.m_pCurTransMat != pNewTransMat)
|
|
{
|
|
m_matrices.m_pCurTransMat = pNewTransMat;
|
|
|
|
m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_matView.SetIdentity();
|
|
m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_matProj = *pNewTransMat;
|
|
}
|
|
|
|
// set alpha blending mode
|
|
switch (renderFlags.GetAlphaBlendMode())
|
|
{
|
|
case e_AlphaAdditive:
|
|
{
|
|
curRenderStates |= GS_BLSRC_ONE | GS_BLDST_ONE;
|
|
break;
|
|
}
|
|
case e_AlphaBlended:
|
|
{
|
|
curRenderStates |= GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
|
|
break;
|
|
}
|
|
case e_AlphaNone:
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// set fill mode
|
|
switch (renderFlags.GetFillMode())
|
|
{
|
|
case e_FillModeWireframe:
|
|
{
|
|
curRenderStates |= GS_WIREFRAME;
|
|
break;
|
|
}
|
|
case e_FillModeSolid:
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// set cull mode
|
|
switch (renderFlags.GetCullMode())
|
|
{
|
|
case e_CullModeNone:
|
|
{
|
|
m_renderer.SetCullMode(R_CULL_NONE);
|
|
break;
|
|
}
|
|
case e_CullModeFront:
|
|
{
|
|
m_renderer.SetCullMode(R_CULL_FRONT);
|
|
break;
|
|
}
|
|
case e_CullModeBack:
|
|
default:
|
|
{
|
|
m_renderer.SetCullMode(R_CULL_BACK);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// set depth write mode
|
|
switch (renderFlags.GetDepthWriteFlag())
|
|
{
|
|
case e_DepthWriteOff:
|
|
{
|
|
break;
|
|
}
|
|
case e_DepthWriteOn:
|
|
default:
|
|
{
|
|
curRenderStates |= GS_DEPTHWRITE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// set depth test mode
|
|
switch (renderFlags.GetDepthTestFlag())
|
|
{
|
|
case e_DepthTestOff:
|
|
{
|
|
curRenderStates |= GS_NODEPTHTEST;
|
|
break;
|
|
}
|
|
case e_DepthTestOn:
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// set point size
|
|
uint8 newPointSize(m_curPointSize);
|
|
if (CAuxGeomCB::e_PtList == CAuxGeomCB::GetPrimType(renderFlags))
|
|
{
|
|
newPointSize = CAuxGeomCB::GetPointSize(renderFlags);
|
|
}
|
|
else
|
|
{
|
|
newPointSize = 1;
|
|
}
|
|
|
|
if (newPointSize != m_curPointSize)
|
|
{
|
|
assert(newPointSize > 0);
|
|
float pointSize((float) newPointSize);
|
|
assert(0);
|
|
m_curPointSize = newPointSize;
|
|
}
|
|
|
|
// apply states
|
|
m_renderer.FX_SetState(curRenderStates);
|
|
|
|
// set color operations
|
|
m_renderer.EF_SetColorOp(eCO_REPLACE, eCO_REPLACE, (eCA_Diffuse | (eCA_Diffuse << 3)), (eCA_Diffuse | (eCA_Diffuse << 3)));
|
|
m_renderer.EF_SetSrgbWrite(false);
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::RT_Flush(SAuxGeomCBRawDataPackaged& data, size_t begin, size_t end, bool reset)
|
|
{
|
|
if (!CV_r_auxGeom)
|
|
{
|
|
return;
|
|
}
|
|
|
|
PROFILE_LABEL_SCOPE("AuxGeom");
|
|
|
|
// should only be called from render thread
|
|
assert(m_renderer.m_pRT->IsRenderThread());
|
|
|
|
assert(data.m_pData);
|
|
|
|
if (begin < end)
|
|
{
|
|
m_pCurCBRawData = data.m_pData;
|
|
|
|
Matrix44A origMatProj = m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_matProj;
|
|
Matrix44A origMatView = m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_matView;
|
|
|
|
if (false == m_renderer.IsDeviceLost())
|
|
{
|
|
// prepare rendering
|
|
PrepareRendering();
|
|
|
|
// get push buffer to process all submitted auxiliary geometries
|
|
m_pCurCBRawData->GetSortedPushBuffer(begin, end, m_auxSortedPushBuffer);
|
|
|
|
// process push buffer
|
|
for (CAuxGeomCB::AuxSortedPushBuffer::const_iterator it(m_auxSortedPushBuffer.begin()), itEnd(m_auxSortedPushBuffer.end()); it != itEnd; )
|
|
{
|
|
// mark current push buffer position
|
|
CAuxGeomCB::AuxSortedPushBuffer::const_iterator itCur(it);
|
|
|
|
// get current render flags
|
|
const SAuxGeomRenderFlags& curRenderFlags((*itCur)->m_renderFlags);
|
|
m_curTransMatrixIdx = (*itCur)->m_transMatrixIdx;
|
|
|
|
// get prim type
|
|
CAuxGeomCB::EPrimType primType(CAuxGeomCB::GetPrimType(curRenderFlags));
|
|
|
|
// find all entries sharing the same render flags
|
|
while (true)
|
|
{
|
|
++it;
|
|
if ((it == itEnd) || ((*it)->m_renderFlags != curRenderFlags) || ((*it)->m_transMatrixIdx != m_curTransMatrixIdx))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Adjust render states based on current render flags and m_curTransMatrixIdx
|
|
AdjustRenderStates(curRenderFlags);
|
|
// Force the constant buffer to update the camera info - AdjustRenderStates() may have changed the projection matrix.
|
|
m_renderer.RT_SetCameraInfo();
|
|
|
|
// prepare thick lines
|
|
if (CAuxGeomCB::e_TriList == primType && false != CAuxGeomCB::IsThickLine(curRenderFlags))
|
|
{
|
|
if (e_Mode3D == curRenderFlags.GetMode2D3DFlag())
|
|
{
|
|
PrepareThickLines3D(itCur, it);
|
|
}
|
|
else
|
|
{
|
|
PrepareThickLines2D(itCur, it);
|
|
}
|
|
}
|
|
|
|
// set appropriate shader
|
|
SetShader(curRenderFlags);
|
|
|
|
// draw push buffer entries
|
|
switch (primType)
|
|
{
|
|
case CAuxGeomCB::e_PtList:
|
|
case CAuxGeomCB::e_LineList:
|
|
case CAuxGeomCB::e_TriList:
|
|
{
|
|
DrawAuxPrimitives(itCur, it, primType);
|
|
}
|
|
break;
|
|
case CAuxGeomCB::e_LineListInd:
|
|
case CAuxGeomCB::e_TriListInd:
|
|
{
|
|
DrawAuxIndexedPrimitives(itCur, it, primType);
|
|
}
|
|
break;
|
|
case CAuxGeomCB::e_Obj:
|
|
default:
|
|
{
|
|
DrawAuxObjects(itCur, it);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_matProj = origMatProj;
|
|
m_renderer.m_RP.m_TI[m_renderer.m_RP.m_nProcessThreadID].m_matView = origMatView;
|
|
|
|
m_pCurCBRawData = 0;
|
|
m_curTransMatrixIdx = 0;
|
|
}
|
|
|
|
if (reset)
|
|
{
|
|
FlushTextMessages(data.m_pData->m_TextMessages, true);
|
|
data.m_pData->SetUsed(false);
|
|
}
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::Flush(SAuxGeomCBRawDataPackaged& data, size_t begin, size_t end, bool reset)
|
|
{
|
|
m_renderer.m_pRT->RC_AuxFlush(this, data, begin, end, reset);
|
|
}
|
|
|
|
void CRenderAuxGeomD3D::FlushTextMessages(CTextMessages& tMessages, bool reset)
|
|
{
|
|
gRenDev->RenderTextMessages(tMessages);
|
|
tMessages.Clear(!reset);
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::SetOrthoMode(bool enable, Matrix44A* pMatrix)
|
|
{
|
|
GetRenderAuxGeom()->SetOrthoMode(enable, pMatrix);
|
|
}
|
|
|
|
|
|
const Matrix44A& CRenderAuxGeomD3D::GetCurrentView() const
|
|
{
|
|
return IsOrthoMode() ? gRenDev->m_IdentityMatrix : m_matrices.m_matView;
|
|
}
|
|
|
|
|
|
const Matrix44A& CRenderAuxGeomD3D::GetCurrentViewInv() const
|
|
{
|
|
return IsOrthoMode() ? gRenDev->m_IdentityMatrix : m_matrices.m_matViewInv;
|
|
}
|
|
|
|
|
|
const Matrix44A& CRenderAuxGeomD3D::GetCurrentProj() const
|
|
{
|
|
return IsOrthoMode() ? GetAuxOrthoMatrix(m_curTransMatrixIdx) : m_matrices.m_matProj;
|
|
}
|
|
|
|
|
|
const Matrix44A& CRenderAuxGeomD3D::GetCurrentTrans3D() const
|
|
{
|
|
return IsOrthoMode() ? GetAuxOrthoMatrix(m_curTransMatrixIdx) : m_matrices.m_matTrans3D;
|
|
}
|
|
|
|
|
|
const Matrix44A& CRenderAuxGeomD3D::GetCurrentTrans2D() const
|
|
{
|
|
return m_matrices.m_matTrans2D;
|
|
}
|
|
|
|
|
|
bool CRenderAuxGeomD3D::IsOrthoMode() const
|
|
{
|
|
return m_curTransMatrixIdx != -1;
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::SMatrices::UpdateMatrices(CD3D9Renderer& renderer)
|
|
{
|
|
renderer.GetModelViewMatrix(&m_matView.m00);
|
|
renderer.GetProjectionMatrix(&m_matProj.m00);
|
|
|
|
m_matViewInv = m_matView.GetInverted();
|
|
m_matTrans3D = m_matView * m_matProj;
|
|
|
|
m_pCurTransMat = 0;
|
|
}
|
|
|
|
|
|
void CRenderAuxGeomD3D::FreeMemory()
|
|
{
|
|
m_auxGeomCBCol.FreeMemory();
|
|
|
|
stl::free_container(m_auxSortedPushBuffer);
|
|
}
|
|
|
|
void CRenderAuxGeomD3D::Process()
|
|
{
|
|
m_auxGeomCBCol.Process();
|
|
}
|
|
|
|
CAuxGeomCB* CRenderAuxGeomD3D::GetRenderAuxGeom(void* jobID)
|
|
{
|
|
return m_auxGeomCBCol.Get(this, jobID);
|
|
}
|
|
|
|
|
|
inline const CAuxGeomCB::AuxVertexBuffer& CRenderAuxGeomD3D::GetAuxVertexBuffer() const
|
|
{
|
|
assert(m_pCurCBRawData);
|
|
return m_pCurCBRawData->m_auxVertexBuffer;
|
|
}
|
|
|
|
|
|
inline const CAuxGeomCB::AuxIndexBuffer& CRenderAuxGeomD3D::GetAuxIndexBuffer() const
|
|
{
|
|
assert(m_pCurCBRawData);
|
|
return m_pCurCBRawData->m_auxIndexBuffer;
|
|
}
|
|
|
|
|
|
inline const CAuxGeomCB::AuxDrawObjParamBuffer& CRenderAuxGeomD3D::GetAuxDrawObjParamBuffer() const
|
|
{
|
|
assert(m_pCurCBRawData);
|
|
return m_pCurCBRawData->m_auxDrawObjParamBuffer;
|
|
}
|
|
|
|
|
|
inline const Matrix44A& CRenderAuxGeomD3D::GetAuxOrthoMatrix(int idx) const
|
|
{
|
|
assert(m_pCurCBRawData && idx >= 0 && idx < (int)m_pCurCBRawData->m_auxOrthoMatrices.size());
|
|
return m_pCurCBRawData->m_auxOrthoMatrices[idx];
|
|
}
|
|
|
|
void CRenderAuxGeomD3D::SDrawObjMesh::Release()
|
|
{
|
|
gcpRendD3D->m_DevMan.ReleaseD3D11Buffer(m_pVB);
|
|
m_pVB = nullptr;
|
|
|
|
gcpRendD3D->m_DevMan.ReleaseD3D11Buffer(m_pIB);
|
|
m_pIB = nullptr;
|
|
|
|
m_numVertices = 0;
|
|
m_numFaces = 0;
|
|
}
|
|
|
|
#endif // #if defined(ENABLE_RENDER_AUX_GEOM)
|