Skip to content
Snippets Groups Projects
Select Git revision
  • develop
  • master default protected
  • v0.5
  • v0.4b
  • v0.3b
  • v0.2b
  • v0.1b
7 results

MeshPrimitive.cpp

Blame
  • MeshPrimitive.cpp 11.22 KiB
    ////////////////////////////////////////////////////////////////////////////////
    //Copyright 2014 Andrew Cohen, Eric Wait, and Mark Winter
    //This file is part of LEVER 3-D - the tool for 5-D stem cell segmentation,
    //tracking, and lineaging. See http://bioimage.coe.drexel.edu 'software' section
    //for details. LEVER 3-D is free software: you can redistribute it and/or modify
    //it under the terms of the GNU General Public License as published by the Free
    //Software Foundation, either version 3 of the License, or (at your option) any
    //later version.
    //LEVER 3-D is distributed in the hope that it will be useful, but WITHOUT ANY
    //WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
    //A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
    //You should have received a copy of the GNU General Public License along with
    //LEVer in file "gnu gpl v3.txt".  If not, see  <http://www.gnu.org/licenses/>.
    ////////////////////////////////////////////////////////////////////////////////
    
    #include "MeshPrimitive.h"
    #include "Global/Globals.h"
    #include "Global/ErrorMsg.h"
    
    #include <limits>
    
    
    const Vec<uint32_t> MeshPrimitive::unitQuadIdx[2] =
    		{Vec<uint32_t>(0,1,3),
    		Vec<uint32_t>(1,2,3)};
    
    const Vec<float> MeshPrimitive::unitQuadVerts[4] =
    		{Vec<float>(-0.5f, -0.5f, 0.0f),
    		Vec<float>(-0.5f, 0.5f, 0.0f),
    		Vec<float>(0.5f, 0.5f, 0.0f),
    		Vec<float>(0.5f, -0.5f, 0.0f)};
    
    const Vec<float> MeshPrimitive::unitQuadNorms[4] =
    		{Vec<float>(0.0f, 0.0f, -1.0f),
    		Vec<float>(0.0f, 0.0f, -1.0f),
    		Vec<float>(0.0f, 0.0f, -1.0f),
    		Vec<float>(0.0f, 0.0f, -1.0f)};
    
    
    
    MeshPrimitive::MeshPrimitive(Renderer* rendererIn, VertexLayout::Types layoutType, const std::string& shaderFile, const std::string& shaderFunc)
    	: renderer(rendererIn), layout(layoutType), vertShaderIdx(-1), vertexBuffer(NULL), indexBuffer(NULL)
    {
    	loadShader(shaderFile,shaderFunc);
    }
    
    
    MeshPrimitive::MeshPrimitive(Renderer* rendererIn,
    	const std::vector<Vec<uint32_t>>& faces, const std::vector<Vec<float>>& vertices,
    	const std::vector<Vec<float>>& normals, const std::vector<Vec<float>>& textureUV, const std::vector<Color>& colors)
    	: MeshPrimitive(rendererIn)
    {
    	setupMesh(faces, vertices, normals, textureUV, colors);
    	initializeResources();
    }
    
    void MeshPrimitive::setupMesh(const std::vector<Vec<uint32_t>>& facesIn, const std::vector<Vec<float>>& verticesIn,
    	const std::vector<Vec<float>>& normalsIn, const std::vector<Vec<float>>& texUVsIn, const std::vector<Color>& colorsIn)
    {
    	faces = facesIn;
    	vertices = verticesIn;
    	normals = normalsIn;
    	texUVs = texUVsIn;
    	colors = colorsIn;
    
    	updateCenterOfMass();
    }
    
    void MeshPrimitive::cleanupMesh()
    {
    	numFaces = 0;
    
    	SAFE_RELEASE(vertexBuffer);
    	SAFE_RELEASE(indexBuffer);
    }
    
    void MeshPrimitive::loadShader(const std::string& shaderFile, const std::string& shaderFunc)
    {
    	vertShaderIdx = renderer->registerVertexShader(shaderFile,shaderFunc, layout);
    }
    
    void MeshPrimitive::initializeResources(UINT vertAccessFlags, UINT indexAccessFlags)
    {
    	cleanupMesh();
    
    	numFaces = faces.size();
    	numVerts = vertices.size();
    
    	D3D11_USAGE vertUsage = (( vertAccessFlags != 0 ) ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_IMMUTABLE);
    	D3D11_USAGE indexUsage = (( indexAccessFlags != 0 ) ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_IMMUTABLE);
    
    	void* initData = layout.allocLayout(numVerts);
    
    	layout.sliceIntoLayout(initData, VertexLayout::Attributes::Position, numVerts, (float*)(vertices.data()));
    
    	if ( layout.validAttribute(VertexLayout::Attributes::Normal) && normals.size() > 0 )
    		layout.sliceIntoLayout(initData, VertexLayout::Attributes::Normal, numVerts, (float*)(normals.data()));
    
    	if ( layout.validAttribute(VertexLayout::Attributes::TextureUV) && texUVs.size() > 0 )
    		layout.sliceIntoLayout(initData, VertexLayout::Attributes::TextureUV, numVerts, (float*)(texUVs.data()));
    
    	if ( layout.validAttribute(VertexLayout::Attributes::Color) && colors.size() > 0 )
    		layout.sliceIntoLayout(initData, VertexLayout::Attributes::Color, numVerts, (float*)(colors.data()));
    
    	size_t bufferSize = numVerts * layout.getVertSize();
    	HRESULT hr = renderer->createVertexBuffer(vertAccessFlags, vertUsage, bufferSize, initData, &vertexBuffer);
    	if (FAILED(hr))
    		sendHrErrMessage(hr);
    
    	hr = renderer->createIndexBuffer(indexAccessFlags, indexUsage, faces, &indexBuffer);
    	if (FAILED(hr))
    		sendHrErrMessage(hr);
    }
    
    void MeshPrimitive::updateCenterOfMass()
    {
    	centerOfMass = Vec<float>(0.0f, 0.0f, 0.0f);
    
    	for ( int i=0; i < vertices.size(); ++i )
    		centerOfMass += vertices[i];
    
    	centerOfMass = centerOfMass / vertices.size();
    }
    
    bool MeshPrimitive::intersectTriangle(Vec<uint32_t> face, Vec<float> lclPntVec, Vec<float> lclDirVec, Vec<float>& triCoord)
    {
    	// Find vectors for two edges sharing vert0
    	Vec<float> edge1(vertices[face.y]-vertices[face.x]);
    	Vec<float> edge2(vertices[face.z]-vertices[face.x]);
    
    	Vec<float> crossVec = Vec<float>::cross(lclDirVec,edge2);
    
    	// If determinant is near zero, ray lies in plane of triangle
    	float det = Vec<float>::dot(edge1,crossVec);
    
    	if( abs(det) < 1e-5f )
    		return false;
    
    	Vec<float> tvec;
    	if( det > 0 )
    	{
    		tvec = lclPntVec - vertices[face.x];
    	}
    	else
    	{
    		tvec = lclPntVec + vertices[face.x];
    		det = -det;
    	}
    
    	// Calculate U parameter and test bounds
    	triCoord.x = Vec<float>::dot(tvec,crossVec);
    	if( triCoord.x < 0.0f || triCoord.x > det )
    		return false;
    
    	// Prepare to test V parameter
    	Vec<float> qvec = Vec<float>::cross(tvec,edge1);
    
    	// Calculate V parameter and test bounds
    	triCoord.y = Vec<float>::dot(lclDirVec,qvec);
    	if( triCoord.y < 0.0f || triCoord.x + triCoord.y > det )
    		return false;
    
    	// Calculate t, scale parameters, ray intersects triangle
    	triCoord.z = Vec<float>::dot(edge2,qvec);
    
    	triCoord = triCoord / det;
    
    	return true;
    }
    
    bool MeshPrimitive::checkIntersect(Vec<float> lclPntVec, Vec<float> lclDirVec, float & depthOut)
    {
    	bool found = false;
    	depthOut = std::numeric_limits<float>::max();
    
    	for (uint32_t i=0; i < faces.size(); ++i){
    		Vec<float> triCoord;
    
    		if ( intersectTriangle(faces[i],lclPntVec,lclDirVec,triCoord) )
    		{
    			if ( triCoord.z < depthOut && triCoord.z > 0)
    			{
    				depthOut = triCoord.z;
    				found = true;
    			}
    		}
    	}
    
    	return found;
    }
    
    MeshPrimitive::~MeshPrimitive()
    {
    	cleanupMesh();
    
    	renderer = NULL;
    	vertShaderIdx = -1;
    }
    
    
    
    StaticColorMesh::StaticColorMesh(Renderer* renderer, const std::vector<Vec<uint32_t>>& faces,
    	const std::vector<Vec<float>>& vertices, const std::vector<Vec<float>>& normals, const Color& color)
    	: MeshPrimitive(renderer, VertexLayout::Types::PNC, "StaticColorShader", "StaticColorVS_PNC")
    {
    	setupMesh(faces, vertices, normals);
    
    	// Make a per-vertex color property
    	colors.resize(vertices.size());
    	for ( int i=0; i < vertices.size(); ++i )
    		colors[i] = color;
    
    	initializeResources();
    }
    
    StaticColorMesh::StaticColorMesh(Renderer* renderer, const std::vector<Vec<uint32_t>>& faces, const std::vector<Vec<float>>& vertices,
    	const std::vector<Vec<float>>& normals, const std::vector<Color>& colors)
    	: MeshPrimitive(renderer, VertexLayout::Types::PNC, "StaticColorShader", "StaticColorVS_PNC")
    {
    	setupMesh(faces, vertices, normals, std::vector<Vec<float>>(), colors);
    	initializeResources();
    }
    
    Color StaticColorMesh::getColor()
    {
    	if ( colors.size() > 0 )
    		return colors[0];
    
    	return Color(1.0f, 1.0f, 1.0f, 1.0f);
    }
    
    
    
    TextQuads::TextQuads(Renderer* renderer, size_t maxQuads)
    	: MeshPrimitive(renderer, VertexLayout::Types::PTCC, "TextShader", "TextQuadVS_PTCC"), maxQuads(maxQuads)
    {
    	maxFaces = 2*maxQuads;
    
    	faces.resize(maxFaces);
    	vertices.resize(4*maxQuads);
    
    	for ( int i=0; i < maxQuads; ++i )
    	{
    		faces[2 * i] = unitQuadIdx[0] + 4 * i;
    		faces[2 * i + 1] = unitQuadIdx[1] + 4 * i;
    	}
    
    	initializeResources(D3D11_CPU_ACCESS_WRITE);
    
    	// Will dyanmically update the quads later
    	clearQuads();
    }
    
    void TextQuads::clearQuads()
    {
    	numFaces = 0;
    	numVerts = 0;
    
    	faces.clear();
    	vertices.clear();
    	texUVs.clear();
    	colors.clear();
    	backColors.clear();
    
    	// allocate memory for the quads
    	vertices.reserve(4*maxQuads);
    	texUVs.reserve(4*maxQuads);
    	colors.reserve(4*maxQuads);
    	backColors.reserve(4*maxQuads);
    }
    
    bool TextQuads::addQuad(const Vec<float> pos[4], const Vec<float> uv[4], const Color& color, const Color& backColor)
    {
    	assert(vertices.size() <= 4*maxQuads);
    
    	if ( numFaces == maxFaces )
    		return false;
    
    	for ( int i=0; i < 4; ++i )
    	{
    		vertices.push_back(pos[i]);
    		texUVs.push_back(uv[i]);
    
    		colors.push_back(color);
    		backColors.push_back(backColor);
    	}
    
    	numVerts = vertices.size();
    	numFaces += 2;
    
    	return true;
    }
    
    void TextQuads::updateResources()
    {
    	if ( numFaces == 0 )
    		return;
    
    
    	D3D11_MAPPED_SUBRESOURCE res;
    	gRenderer->lockBuffer(vertexBuffer, D3D11_MAP_WRITE_DISCARD, res);
    
    	layout.sliceIntoLayout(res.pData, VertexLayout::Attributes::Position, numVerts, (float*)vertices.data());
    	layout.sliceIntoLayout(res.pData, VertexLayout::Attributes::TextureUV, numVerts, (float*)texUVs.data());
    	layout.sliceIntoLayout(res.pData, VertexLayout::Attributes::Color, numVerts, (float*)colors.data());
    	layout.sliceIntoLayout(res.pData, VertexLayout::Attributes::ColorBack, numVerts, (float*)backColors.data());
    
    	gRenderer->releaseBuffer(vertexBuffer);
    }
    
    
    
    ViewAlignedPlanes::ViewAlignedPlanes(Renderer* renderer, Vec<size_t> volDims, Vec<float> scaleDims)
    	: MeshPrimitive(renderer, VertexLayout::Types::PT, "ViewAlignedVS","ViewAlignedVS_PT"),
    	dims(volDims), physicalSize(scaleDims)
    {
    	buildViewAlignedPlanes(dims, faces, vertices, texUVs);
    
    	initializeResources();
    }
    
    DirectX::XMMATRIX ViewAlignedPlanes::computeLocalToWorld(DirectX::XMMATRIX parentToWorld_dx)
    {
    	Eigen::Matrix4f parentToWorld = ConvertMatrix(parentToWorld_dx);
    
    	Eigen::Matrix4f textureCoordinateCorrection;
    	textureCoordinateCorrection<<
    		0.0f, 1.0f, 0.0f, 0.0f,
    		1.0f, 0.0f, 0.0f, 0.0f,
    		0.0f, 0.0f, 1.0f, 0.0f,
    		0.0f, 0.0f, 0.0f, 1.0f;
    
    	Vec<float> physicalScaling = physicalSize / physicalSize.maxValue();
    
    	Eigen::Affine3f compute(Eigen::Translation3f(0.5f, 0.5f, 0.5f));
    	compute *= Eigen::Scaling(1.0f/physicalScaling.x, 1.0f/physicalScaling.y, 1.0f/physicalScaling.z);
    	compute *= Eigen::Scaling(0.5f, 0.5f, 0.5f);
    	compute *= textureCoordinateCorrection;
    	compute *= parentToWorld.inverse();
    	compute *= Eigen::Scaling(2.0f, 2.0f, 2.0f);
    	compute *= Eigen::Translation3f(-0.5f, -0.5f, -0.5f);
    
    	return ConvertMatrix(compute.matrix());
    }
    
    void ViewAlignedPlanes::buildViewAlignedPlanes(Vec<size_t> volDims, std::vector<Vec<uint32_t>>& faces,
    	std::vector<Vec<float>>& vertices,std::vector<Vec<float>>& textureUV)
    {
    	//3.0 is to reduce moire
    	const float samplePadding = 3.0/2.0;
    
    	faces.clear();
    	vertices.clear();
    	textureUV.clear();
    
    	int numPlanes = int(volDims.maxValue() * 2.0f * Renderer::cornerVolumeDist * samplePadding);
    	renderer->setNumPlanes((int)(ceil(numPlanes / Renderer::cornerVolumeDist)));
    
    	vertices.resize(4*numPlanes);
    	faces.resize(2*numPlanes);
    	textureUV.resize(4*numPlanes);
    
    	int planesFirstVert = 0;
    	for (int planeIdx=0; planeIdx<numPlanes; ++planeIdx)
    	{
    		float zPosition = (2.0f*planeIdx) / numPlanes -1.0f;
    
    		//i is making each plane
    		for (int i=0; i<4; i++)
    		{
    			vertices[planesFirstVert+i] = 2.0f * unitQuadVerts[i] * 2.0f * Renderer::cornerVolumeDist;
    			vertices[planesFirstVert+i].z = zPosition * Renderer::cornerVolumeDist;
    
    			textureUV[planesFirstVert+i] = vertices[planesFirstVert+i] * 0.5f + 0.5f;
    		}
    
    		for (int i=0; i<2; ++i)
    			faces[2*(numPlanes-planeIdx-1) + i] = unitQuadIdx[i] + planesFirstVert;
    
    		planesFirstVert += 4;
    	}
    }