249 lines
6.4 KiB
C++
249 lines
6.4 KiB
C++
// modelgeometry.cpp
|
|
//
|
|
// Copyright (C) 2004-2010, Celestia Development Team
|
|
// Original version by Chris Laurel <claurel@gmail.com>
|
|
//
|
|
// This program 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 2
|
|
// of the License, or (at your option) any later version.
|
|
|
|
#include "modelgeometry.h"
|
|
#include "rendcontext.h"
|
|
#include "texmanager.h"
|
|
#include <Eigen/Core>
|
|
#include <functional>
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
|
|
using namespace cmod;
|
|
using namespace Eigen;
|
|
using namespace std;
|
|
|
|
|
|
|
|
// Vertex buffer object support
|
|
|
|
// VBO optimization is only worthwhile for large enough vertex lists
|
|
static const unsigned int MinVBOSize = 4096;
|
|
static bool VBOSupportTested = false;
|
|
static bool VBOSupported = false;
|
|
|
|
static bool isVBOSupported()
|
|
{
|
|
if (!VBOSupportTested)
|
|
{
|
|
VBOSupportTested = true;
|
|
VBOSupported = (GLEW_ARB_vertex_buffer_object == GL_TRUE);
|
|
}
|
|
|
|
return VBOSupported;
|
|
}
|
|
|
|
|
|
class ModelOpenGLData
|
|
{
|
|
public:
|
|
ModelOpenGLData()
|
|
{
|
|
}
|
|
|
|
~ModelOpenGLData()
|
|
{
|
|
for (vector<GLuint>::iterator iter = vbos.begin(); iter != vbos.end(); ++iter)
|
|
{
|
|
GLuint vboId = *iter;
|
|
if (vboId != 0)
|
|
{
|
|
glDeleteBuffersARB(1, &vboId);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<GLuint> vbos; // vertex buffer objects
|
|
};
|
|
|
|
|
|
/** Create a new ModelGeometry wrapping the specified model.
|
|
* The ModelGeoemtry takes ownership of the model.
|
|
*/
|
|
ModelGeometry::ModelGeometry(Model* model) :
|
|
m_model(model),
|
|
m_vbInitialized(false),
|
|
m_glData(NULL)
|
|
{
|
|
m_glData = new ModelOpenGLData();
|
|
}
|
|
|
|
|
|
ModelGeometry::~ModelGeometry()
|
|
{
|
|
delete m_model;
|
|
delete m_glData;
|
|
}
|
|
|
|
|
|
bool
|
|
ModelGeometry::pick(const Ray3d& r, double& distance) const
|
|
{
|
|
return m_model->pick(r.origin, r.direction, distance);
|
|
}
|
|
|
|
|
|
/*! Render the model; the time parameter is ignored right now
|
|
* since this class doesn't currently support animation.
|
|
*/
|
|
void
|
|
ModelGeometry::render(RenderContext& rc, double /* t */)
|
|
{
|
|
// The first time the mesh is rendered, we will try and place the
|
|
// vertex data in a vertex buffer object and potentially get a huge
|
|
// rendering performance boost. This can consume a great deal of
|
|
// memory, since we're duplicating the vertex data. TODO: investigate
|
|
// the possibility of deleting the original data. We can always map
|
|
// read-only later on for things like picking, but this could be a low
|
|
// performance path.
|
|
if (!m_vbInitialized && isVBOSupported())
|
|
{
|
|
m_vbInitialized = true;
|
|
|
|
for (unsigned int i = 0; i < m_model->getMeshCount(); ++i)
|
|
{
|
|
Mesh* mesh = m_model->getMesh(i);
|
|
const Mesh::VertexDescription& vertexDesc = mesh->getVertexDescription();
|
|
|
|
GLuint vboId = 0;
|
|
if (mesh->getVertexCount() * vertexDesc.stride > MinVBOSize)
|
|
{
|
|
glGenBuffersARB(1, &vboId);
|
|
if (vboId != 0)
|
|
{
|
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId);
|
|
glBufferDataARB(GL_ARRAY_BUFFER_ARB,
|
|
mesh->getVertexCount() * vertexDesc.stride,
|
|
mesh->getVertexData(),
|
|
GL_STATIC_DRAW_ARB);
|
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
|
}
|
|
}
|
|
|
|
m_glData->vbos.push_back(vboId);
|
|
}
|
|
}
|
|
|
|
unsigned int lastMaterial = ~0u;
|
|
unsigned int materialCount = m_model->getMaterialCount();
|
|
|
|
// Iterate over all meshes in the model
|
|
for (unsigned int meshIndex = 0; meshIndex < m_model->getMeshCount(); ++meshIndex)
|
|
{
|
|
Mesh* mesh = m_model->getMesh(meshIndex);
|
|
GLuint vboId = 0;
|
|
|
|
if (m_glData && meshIndex < m_glData->vbos.size())
|
|
{
|
|
vboId = m_glData->vbos[meshIndex];
|
|
}
|
|
|
|
if (vboId != 0)
|
|
{
|
|
// Bind the vertex buffer object.
|
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId);
|
|
rc.setVertexArrays(mesh->getVertexDescription(), NULL);
|
|
}
|
|
else
|
|
{
|
|
// No vertex buffer object; just use normal vertex arrays
|
|
rc.setVertexArrays(mesh->getVertexDescription(), mesh->getVertexData());
|
|
}
|
|
|
|
// Iterate over all primitive groups in the mesh
|
|
for (unsigned int groupIndex = 0; groupIndex < mesh->getGroupCount(); ++groupIndex)
|
|
{
|
|
const Mesh::PrimitiveGroup* group = mesh->getGroup(groupIndex);
|
|
|
|
// Set up the material
|
|
const Material* material = NULL;
|
|
unsigned int materialIndex = group->materialIndex;
|
|
if (materialIndex != lastMaterial && materialIndex < materialCount)
|
|
{
|
|
material = m_model->getMaterial(materialIndex);
|
|
}
|
|
|
|
rc.setMaterial(material);
|
|
rc.drawGroup(*group);
|
|
}
|
|
|
|
// If we set a VBO, unbind it.
|
|
if (vboId != 0)
|
|
{
|
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
ModelGeometry::isOpaque() const
|
|
{
|
|
return m_model->isOpaque();
|
|
}
|
|
|
|
|
|
bool
|
|
ModelGeometry::isNormalized() const
|
|
{
|
|
return m_model->isNormalized();
|
|
}
|
|
|
|
|
|
bool
|
|
ModelGeometry::usesTextureType(Material::TextureSemantic t) const
|
|
{
|
|
return m_model->usesTextureType(t);
|
|
}
|
|
|
|
|
|
void
|
|
ModelGeometry::loadTextures()
|
|
{
|
|
#if 0
|
|
for (vector<const Material*>::const_iterator iter = materials.begin();
|
|
iter != materials.end(); iter++)
|
|
{
|
|
const Mesh::Material* m = *iter;
|
|
|
|
if (m->maps[Mesh::DiffuseMap] != InvalidResource)
|
|
GetTextureManager()->find(m->maps[Mesh::DiffuseMap]);
|
|
if (m->maps[Mesh::NormalMap] != InvalidResource)
|
|
GetTextureManager()->find(m->maps[Mesh::NormalMap]);
|
|
if (m->maps[Mesh::SpecularMap] != InvalidResource)
|
|
GetTextureManager()->find(m->maps[Mesh::SpecularMap]);
|
|
if (m->maps[Mesh::EmissiveMap] != InvalidResource)
|
|
GetTextureManager()->find(m->maps[Mesh::EmissiveMap]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
string
|
|
CelestiaTextureResource::source() const
|
|
{
|
|
if (m_textureHandle == InvalidResource)
|
|
{
|
|
return "";
|
|
}
|
|
else
|
|
{
|
|
const TextureInfo* t = GetTextureManager()->getResourceInfo(textureHandle());
|
|
if (!t)
|
|
{
|
|
return "";
|
|
}
|
|
else
|
|
{
|
|
return t->source;
|
|
}
|
|
}
|
|
}
|