#include "yUtilsMesh.h"
#include "OgreSubMesh2.h"
#include "Objects/yObject.h"
#include "Graphics/yGraphicsServices.h"
#include "Graphics/yGraphicsSceneNodeManager.h"
#include "OgreSceneManager.h"
#include "OgreBitwise.h"
#include "OgreItem.h"
#include "Vao/OgreAsyncTicket.h"
#include <iostream>
yUtilsMesh::yUtilsMesh( yObject* object )
{
mSceneManager = yGraphicsServices::getGraphicsSceneNodeManager().getMainSceneManager();
mNode = yGraphicsServices::getGraphicsSceneNodeManager().getObjectNode( object );
mItem = yGraphicsServices::getGraphicsSceneNodeManager().getObjectItem( object );
mMesh = mItem->getMesh();
getMeshInformation( mVertexCount, mVertices, mIndexCount, mIndices, mUVCoords,
Ogre::Vector3::ZERO,
Ogre::Quaternion::IDENTITY,
Ogre::Vector3::UNIT_SCALE
//object->getGraphicsWorldTransform().position,
//object->getGraphicsWorldTransform().orientation,
//object->getGraphicsWorldTransform().scale
);
mClosestIndex = 0;
}
yUtilsMesh::~yUtilsMesh(){
delete mVertices;
delete mIndices;
delete mUVCoords;
mVertices = nullptr;
mIndices = nullptr;
mUVCoords = nullptr;
}
void yUtilsMesh::getMeshInformation(
size_t &vertexCount,
Ogre::Vector3* &vertices,
size_t &indexCount,
Ogre::uint32* &indices,
Ogre::Vector2* &uvCoords,
const Ogre::Vector3 &position,
const Ogre::Quaternion &orient,
const Ogre::Vector3 &scale )
{
yAssert( yUtils::isGraphicsThread(), "graphics method called by logic thread" );
//First, we compute the total number of vertices and indices and init the buffers.
unsigned int numVertices = 0;
unsigned int numIndices = 0;
Ogre::Mesh::SubMeshVec::const_iterator subMeshIterator = mMesh->getSubMeshes().begin();
while (subMeshIterator != mMesh->getSubMeshes().end())
{
Ogre::SubMesh *subMesh = *subMeshIterator;
numVertices += subMesh->mVao[0][0]->getVertexBuffers()[0]->getNumElements();
numIndices += subMesh->mVao[0][0]->getIndexBuffer()->getNumElements();
subMeshIterator++;
}
vertices = new Ogre::Vector3[numVertices];
indices = new Ogre::uint32[numIndices];
uvCoords = new Ogre::Vector2[numIndices];
vertexCount = numVertices;
indexCount = numIndices;
unsigned int addedIndices = 0;
unsigned int index_offset = 0;
unsigned int subMeshOffset = 0;
// Read Submeshes
subMeshIterator = mMesh->getSubMeshes().begin();
while (subMeshIterator != mMesh->getSubMeshes().end())
{
Ogre::SubMesh *subMesh = *subMeshIterator;
Ogre::VertexArrayObjectArray vaos = subMesh->mVao[0];
if (!vaos.empty())
{
//Get the first LOD level
Ogre::VertexArrayObject *vao = vaos[0];
bool indices32 = (vao->getIndexBuffer()->getIndexType() == Ogre::IndexBufferPacked::IT_32BIT);
const Ogre::VertexBufferPackedVec &vertexBuffers = vao->getVertexBuffers();
Ogre::IndexBufferPacked *indexBuffer = vao->getIndexBuffer();
//request async read from buffer
Ogre::VertexArrayObject::ReadRequestsArray requests;
requests.push_back(Ogre::VertexArrayObject::ReadRequests(Ogre::VES_POSITION));
requests.push_back(Ogre::VertexArrayObject::ReadRequests(Ogre::VES_TEXTURE_COORDINATES));
vao->readRequests(requests);
vao->mapAsyncTickets(requests);
unsigned int subMeshVerticiesNum = requests[0].vertexBuffer->getNumElements();
if (requests[0].type == Ogre::VET_HALF4){
for (size_t i = 0; i < subMeshVerticiesNum; ++i){
const Ogre::uint16* pos = reinterpret_cast<const Ogre::uint16*>(requests[0].data);
Ogre::Vector3 vec;
vec.x = Ogre::Bitwise::halfToFloat(pos[0]);
vec.y = Ogre::Bitwise::halfToFloat(pos[1]);
vec.z = Ogre::Bitwise::halfToFloat(pos[2]);
requests[0].data += requests[0].vertexBuffer->getBytesPerElement();
vertices[i + subMeshOffset] = (orient * (vec * scale)) + position;
}
}
else if (requests[0].type == Ogre::VET_FLOAT3){
for (size_t i = 0; i < subMeshVerticiesNum; ++i){
const float* pos = reinterpret_cast<const float*>(requests[0].data);
Ogre::Vector3 vec;
vec.x = *pos++;
vec.y = *pos++;
vec.z = *pos++;
requests[0].data += requests[0].vertexBuffer->getBytesPerElement();
vertices[i + subMeshOffset] = (orient * (vec * scale)) + position;
}
}
else{
//lprint("Error: Vertex Buffer type not recognised in MeshTools::getMeshInformation");
}
//UV COORDINATES
if (requests[1].type == Ogre::VET_HALF2){
for (size_t i = 0; i < subMeshVerticiesNum; ++i){
//const float* pos = reinterpret_cast<const float*>(requests[1].data);
const Ogre::uint16* pos = reinterpret_cast<const Ogre::uint16*>(requests[1].data);
Ogre::Vector2 vec;
vec.x = Ogre::Bitwise::halfToFloat(pos[0]);
vec.y = Ogre::Bitwise::halfToFloat(pos[1]);
requests[1].data += requests[1].vertexBuffer->getBytesPerElement();
uvCoords[i + subMeshOffset] = vec;
}
}
subMeshOffset += subMeshVerticiesNum;
vao->unmapAsyncTickets(requests);
////Read index data
if (indexBuffer)
{
Ogre::AsyncTicketPtr asyncTicket = indexBuffer->readRequest(0, indexBuffer->getNumElements());
unsigned int *pIndices = nullptr;
if( indices32 ) {
pIndices = (unsigned*)(asyncTicket->map());
}
else
{
unsigned short *pShortIndices = (unsigned short*)(asyncTicket->map());
pIndices = new unsigned int[indexBuffer->getNumElements()];
for (size_t k = 0; k < indexBuffer->getNumElements(); k++) pIndices[k] = static_cast<unsigned int>(pShortIndices[k]);
}
unsigned int bufferIndex = 0;
for (size_t i = addedIndices; i < addedIndices + indexBuffer->getNumElements(); i++)
{
indices[i] = pIndices[bufferIndex] + index_offset;
bufferIndex++;
}
addedIndices += indexBuffer->getNumElements();
if (!indices32) delete[] pIndices;
asyncTicket->unmap();
}
index_offset += vertexBuffers[0]->getNumElements();
}
subMeshIterator++;
}
}
Ogre::Vector3 yUtilsMesh::getBarycentricCoordinates(const Ogre::Vector3 &P1, const Ogre::Vector3 &P2, const Ogre::Vector3 &P3, const Ogre::Vector3 &P)
{
//function got it from http://answers.unity3d.com/questions/383804/calculate-uv-coordinates-of-3d-point-on-plane-of-m.html
Ogre::Vector3 f1 = P1 - P;
Ogre::Vector3 f2 = P2 - P;
Ogre::Vector3 f3 = P3 - P;
float a = (P1-P2).crossProduct(P1-P3).length();
float a1 = f2.crossProduct(f3).length() / a;
float a2 = f3.crossProduct(f1).length() / a;
//float a3 = f1.crossProduct(f2).length() / a; // property: a1 + a2 + a3 = 1
return Ogre::Vector3(a1, a2, 1 - a2 - a1);
}
bool yUtilsMesh::getRayIntersectionWithMesh( Ogre::Ray ray, Ogre::Vector3& result )
{
yAssert( yUtils::isGraphicsThread(), "graphics method called by logic thread" );
ray.setOrigin( mNode->_getDerivedOrientation().Inverse() * ( ray.getOrigin() -mNode->_getDerivedPosition() ) );
ray.setDirection( mNode->_getDerivedOrientation().Inverse() * ray.getDirection() );
Ogre::Real closest_distance = -1.0f;
Ogre::Vector3 closest_result;
bool new_closest_found = false;
for(size_t i=0; i<mIndexCount; i+=3){
// check for a hit against this triangle
std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray, mVertices[mIndices[i]], mVertices[mIndices[i+1]], mVertices[mIndices[i+2]], true, false);
// if it was a hit check if its the closest
if( hit.first && (closest_distance < 0.0f || hit.second < closest_distance) )
{
// this is the closest so far, save it off
closest_distance = hit.second;
new_closest_found = true;
mClosestIndex = i;
}
}
if( new_closest_found )
closest_result = ray.getPoint(closest_distance);
mClosestDistance = closest_distance;
// return the result
if( closest_distance >= 0.0f ){
// raycast success
result = closest_result;
return true;
}
// raycast failed
return false;
}
bool yUtilsMesh::getRayIntersectionUVWithMesh( Ogre::Ray ray, Ogre::Vector2& resultUVCoord, float& closestDistance ){
yAssert( yUtils::isGraphicsThread(), "graphics method called by logic thread" );
Ogre::Vector3 result;
bool intersect = getRayIntersectionWithMesh( ray, result );
if( intersect ) {
yAssert( mClosestIndex + 2 < mIndexCount, "invalid index" );
yAssert( mIndices[mClosestIndex] < mVertexCount, "invalid index" );
yAssert( mIndices[mClosestIndex + 1] < mIndexCount, "invalid index" );
yAssert( mIndices[mClosestIndex + 2] < mIndexCount, "invalid index" );
Ogre::Vector3 baryCoord = getBarycentricCoordinates( mVertices[mIndices[mClosestIndex]],
mVertices[mIndices[mClosestIndex + 1]],
mVertices[mIndices[mClosestIndex + 2]],
result );
resultUVCoord = mUVCoords[mIndices[mClosestIndex]] * baryCoord.x +
mUVCoords[mIndices[mClosestIndex + 1]] * baryCoord.y +
mUVCoords[mIndices[mClosestIndex + 2]] * baryCoord.z;
closestDistance = mClosestDistance;
}
return intersect;
}