Page MenuHomePhorge

SubMesh.cpp
No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None

SubMesh.cpp

#include <echo/Graphics/SubMesh.h>
#include <echo/Graphics/Mesh.h>
#include <echo/Kernel/ScopedLock.h>
#include <iostream>
#include <echo/Graphics/RenderTarget.h>
namespace Echo
{
SubMesh::SubMesh(const std::string& name, Mesh& parent) :
mParent(parent),
mAxisAlignedBox(Vector3::ZERO,Vector3::ZERO),
mName(name),
mVisible(true),
mAxisAlignedBoxOutOfDate(true),
mType(MeshTypes::TRIANGLES),
mPointAndLineSize(1.0)
{
}
Vector3 SubMesh::GetDimensions() const
{
UpdateAxisAlignedBox();
return mAxisAlignedBox.GetSize();
}
void SubMesh::SetElementBuffer(shared_ptr<ElementBuffer> elementBuffer)
{
mElementBuffer = elementBuffer;
}
bool SubMesh::SetElementBuffer(ElementBuffer::Type type, ElementBuffer::IndexType indexType, ElementBuffer::ElementType elementType, Size numberOfElements)
{
shared_ptr<ElementBuffer> elementBuffer(new ElementBuffer(type));
if(elementBuffer->Allocate(indexType,elementType, numberOfElements))
{
mElementBuffer = elementBuffer;
return true;
}
return false;
}
void SubMesh::SetVertexBuffer(shared_ptr<VertexBuffer> vertexBuffer)
{
mVertexBuffer = vertexBuffer;
Finalise();
}
shared_ptr<VertexBuffer> SubMesh::GetVertexBuffer(VertexBuffer::Type type)
{
if(!mVertexBuffer)
{
mVertexBuffer.reset(new VertexBuffer(type));
}
return mVertexBuffer;
}
const AxisAlignedBox& SubMesh::GetAxisAlignedBox() const
{
UpdateAxisAlignedBox();
return mAxisAlignedBox;
}
shared_ptr<SubMesh> SubMesh::Clone(Mesh& clonesParent) const
{
SubMesh* newMesh = new SubMesh(mName, clonesParent);
if(mMaterial)
{
newMesh->mMaterial = mMaterial->Clone();
}
if(mOriginalVertices)
{
newMesh->mOriginalVertices = shared_ptr< std::vector<Vector3> >(new std::vector<Vector3>(*mOriginalVertices));
}
if(mBoneWeights)
{
newMesh->mBoneWeights = shared_ptr< std::vector<BoneBinding*> >(new std::vector<BoneBinding*>(*mBoneWeights));
}
if(mVertexBuffer)
{
newMesh->mVertexBuffer.reset(new VertexBuffer(*mVertexBuffer));
}
if(mElementBuffer)
{
newMesh->mElementBuffer.reset(new ElementBuffer(*mElementBuffer));
}
newMesh->mAxisAlignedBox = mAxisAlignedBox;
newMesh->mType = mType;
return shared_ptr<SubMesh>(newMesh);
}
void SubMesh::UpdateAxisAlignedBox() const
{
ScopedLock lock(mAxisAlignedBoxMutex);
if(!mAxisAlignedBoxOutOfDate)
{
return;
}
mAxisAlignedBox.SetNull();
mAxisAlignedBox.SetExtents(Vector3::ZERO,Vector3::ZERO);
if(mVertexBuffer && mVertexBuffer->GetNumberOfElements()!=0)
{
VertexBuffer::Accessor<Vector3> vertices = GetComponents<Vector3>("Position");
if(vertices)
{
Size numberOfElements = mVertexBuffer->GetNumberOfElements();
for(Size i = 0; i < numberOfElements; ++i)
{
mAxisAlignedBox.Merge(vertices[i]);
}
}
}
mAxisAlignedBoxOutOfDate = false;
}
void SubMesh::TranslateVertices(const Vector3& translation)
{
if(!mVertexBuffer)
{
return;
}
//This is faster than performing a matrix operation on each vertex.
VertexBuffer::Accessor<Vector3> vertices = GetComponents<Vector3>("Position");
if(vertices)
{
Size numberOfElements = mVertexBuffer->GetNumberOfElements();
for(Size i = 0; i < numberOfElements; ++i)
{
vertices[i]+=translation;
}
mAxisAlignedBox.Translate(translation);
}
}
SubMesh::~SubMesh()
{
}
void SubMesh::Clear(bool deallocate)
{
if(deallocate)
{
if(mVertexBuffer)
{
mVertexBuffer->Deallocate();
}
if(mElementBuffer)
{
mElementBuffer->Deallocate();
}
} else
{
if(mElementBuffer)
{
mElementBuffer->SetNumberOfElements(0);
}
}
mAxisAlignedBox.SetExtents(Vector3::ZERO,Vector3::ZERO);
mAxisAlignedBoxOutOfDate = true;
}
void SubMesh::SetMaterial(shared_ptr<Material> material)
{
mMaterial = material;
}
void SubMesh::GenerateNormals()
{
// This method is not generalised properly
if(mType!=MeshTypes::TRIANGLES)
{
assert(mType==MeshTypes::TRIANGLES && "GenerateNormals only supports triangle meshes, either add your own support for this type of mesh or request the feature.");
return;
}
if(!mVertexBuffer || !mElementBuffer)
{
return;
}
// Some standard mesh information that you should have lying around.
// vertex is your vertex structure that just contains a normal and position here.
// mVertices is a pointer to the first vertex
// indices is a pointer to the first index
// num_verts is number of mVertices
// num_indices is number of indices
// each face of the mesh is made up of three mVertices.
auto triangles = mElementBuffer->GetAccessor< ElementBuffer::Triangle<u16> >();
VertexBuffer::Accessor<Vector3> vertices = GetComponents<Vector3>("Position");
if(!vertices)
{
return;
}
VertexBuffer::Accessor<Vector3> normals = GetComponents<Vector3>("Normal");
assert(normals && "Normals are not defined for the VertexBuffer");
if(!normals)
{
return;
}
size_t num_vertices = vertices.GetCapacity();
std::vector<Vector3>* normal_buffer = new std::vector<Vector3>[num_vertices];
for(size_t i = 0; i < triangles.GetCapacity(); ++i)
{
// get the three mVertices that make the mFaces
auto triangle = triangles[i];
Vector3 p1 = vertices[ triangle.mA ];
Vector3 p2 = vertices[ triangle.mB ];
Vector3 p3 = vertices[ triangle.mC ];
Vector3 v1 = p2 - p1;
Vector3 v2 = p3 - p1;
Vector3 normal = v1.Cross(v2);
normal.Normalise();
// Store the face's normal for each of the mVertices that make up the face.
normal_buffer[triangle.mA].push_back(normal);
normal_buffer[triangle.mB].push_back(normal);
normal_buffer[triangle.mC].push_back(normal);
}
// Now loop through each vertex vector, and average out all the mNormals stored.
for(size_t i = 0; i < num_vertices; ++i)
{
for(size_t j = 0; j < normal_buffer[i].size(); ++j)
{
normals[i] += normal_buffer[i][j];
}
if(normal_buffer[i].size()!=0)
{
normals[i] /= (f32) (normal_buffer[i].size());
}
normals[i].Normalise();
}
delete [] normal_buffer;
}
Vector3 SubMesh::GetCentre() const
{
UpdateAxisAlignedBox();
return mAxisAlignedBox.GetCentre();
}
void SubMesh::Render(RenderContext& renderContext, const Matrix4& world, const Matrix4& worldView, Colour compoundDiffuse)
{
if(!mVisible || !mVertexBuffer || !mElementBuffer || !mMaterial)
{
return;
}
if(mParent.GetUseSkeleton())
{
ApplyVertexBoneTransforms();
}
mMaterial->ApplyAndRender(renderContext, *this, world, worldView, compoundDiffuse);
}
void SubMesh::GenerateTransformBuffers()
{
if(!mVertexBuffer)
{
return;
}
mOriginalVertices.reset();
VertexBuffer::Accessor<Vector3> vertices = GetComponents<Vector3>("Position");
if(vertices)
{
std::vector<Vector3>* newBuffer = new std::vector<Vector3>(vertices.GetCapacity());
std::vector<Vector3>& dest= *newBuffer;
for(Size i=0; i<vertices.GetCapacity(); ++i)
{
dest[i] = vertices[i];
}
mOriginalVertices = shared_ptr< std::vector<Vector3> >(newBuffer);
}
}
void SubMesh::ApplyVertexBoneTransforms()
{
if(!mVertexBuffer)
{
return;
}
VertexBuffer::Accessor<Vector3> vertices = GetComponents<Vector3>("Position");
if(!vertices)
{
return;
}
std::vector<Vector3>& originalVerts = *mOriginalVertices;
Size numVerts = mVertexBuffer->GetNumberOfElements();
assert(originalVerts.size() == numVerts);
for(Size v = 0; v < numVerts; ++v)
{
BoneBinding& binding = *(*mBoneWeights)[v];
vertices[v].SetZero();
std::map< size_t, f32 >::iterator it = binding.mBoneWeights.begin();
std::map< size_t, f32 >::iterator itEnd = binding.mBoneWeights.end();
while(it != itEnd)
{
const Matrix4& trans = mParent.GetSkeleton()->GetBone(it->first)->GetOffsetTransform();
f32& weight = it->second;
vertices[v].x += (trans[0][0] * originalVerts[v].x +
trans[0][1] * originalVerts[v].y +
trans[0][2] * originalVerts[v].z +
trans[0][3])
* weight;
vertices[v].y += (trans[1][0] * originalVerts[v].x +
trans[1][1] * originalVerts[v].y +
trans[1][2] * originalVerts[v].z +
trans[1][3])
* weight;
vertices[v].z += (trans[2][0] * originalVerts[v].x +
trans[2][1] * originalVerts[v].y +
trans[2][2] * originalVerts[v].z +
trans[2][3])
* weight;
++it;
}
}
mAxisAlignedBoxOutOfDate = true;
mParent.MarkExtentsOutOfDate();
}
void SubMesh::Render(RenderContext& renderContext, const RenderPass& pass, Colour compoundDiffuse)
{
if(!mVertexBuffer)
{
return;
}
RenderTarget& renderTarget = renderContext.mRenderTarget;
// This is for backward compatibility
renderTarget.SetVertexColourEnabled(pass.GetVertexColouringEnabled());
for(Size i = 0; i < pass.GetNumTextureUnits(); ++i)
{
Size setToUse = pass.GetTextureUnit(i)->GetTextureUnitSetToUse();
renderTarget.SetTextureCoordinateSourceIndex(i,setToUse);
}
//Reset the arrays
renderTarget.ClearSources();
renderTarget.SetVertexBuffer(mVertexBuffer);
if(mElementBuffer)
{
if(pass.mProgram)
{
//Make sure the program is built
renderTarget.BuildProgram(pass.mProgram);
// TODO: sort this out
//pass.mProgram->SetAttribute<Vector3>("position",&(*mVertices)[0]);
renderTarget.ActivateProgram(pass.mProgram);
}
renderTarget.DrawElements(*mElementBuffer);
if(pass.mProgram)
{
renderTarget.DeactivateProgram(pass.mProgram);
}
}
// This is for backward compatibility
renderTarget.SetVertexColourEnabled(!pass.GetVertexColouringEnabled());
renderTarget.SetVertexBuffer(nullptr);
}
void SubMesh::MarkExtentsOutOfDate()
{
// This can only come from Mesh when it is marked out of date (someone knows something
// I don't about my data).
mAxisAlignedBoxOutOfDate = true;
}
void SubMesh::Finalise()
{
// When someone knows about my data and tells me but not my Mesh.
mAxisAlignedBoxOutOfDate = true;
mParent.MarkExtentsOutOfDate();
}
}

File Metadata

Mime Type
text/x-c++
Expires
Wed, Jan 15, 8:53 PM (2 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72053
Default Alt Text
SubMesh.cpp (10 KB)

Event Timeline