Index: src/celengine/spheremesh.cpp =================================================================== --- src/celengine/spheremesh.cpp (revision 4952) +++ src/celengine/spheremesh.cpp (working copy) @@ -14,6 +14,7 @@ #include "spheremesh.h" #include +#include #include #include Index: src/celengine/mesh.cpp =================================================================== --- src/celengine/mesh.cpp (revision 4952) +++ src/celengine/mesh.cpp (working copy) @@ -1,746 +0,0 @@ -// mesh.cpp -// -// Copyright (C) 2004-2009, the Celestia Development Team -// Original version by Chris Laurel -// -// 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 "mesh.h" -#include "rendcontext.h" -#include -#include -#include -#include -#include -#include - -using namespace Eigen; -using namespace std; - - -static size_t VertexAttributeFormatSizes[Mesh::FormatMax] = -{ - 4, // Float1 - 8, // Float2 - 12, // Float3 - 16, // Float4, - 4, // UByte4 -}; - - -// 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; -} - - -Mesh::Material::Material() : - diffuse(0.0f, 0.0f, 0.0f), - emissive(0.0f, 0.0f, 0.0f), - specular(0.0f, 0.0f, 0.0f), - specularPower(1.0f), - opacity(1.0f), - blend(NormalBlend) -{ - for (int i = 0; i < TextureSemanticMax; i++) - maps[i] = InvalidResource; - -} - - -Mesh::VertexDescription::VertexDescription(uint32 _stride, - uint32 _nAttributes, - VertexAttribute* _attributes) : - stride(_stride), - nAttributes(_nAttributes), - attributes(NULL) -{ - if (nAttributes != 0) - { - attributes = new VertexAttribute[nAttributes]; - for (uint32 i = 0; i < nAttributes; i++) - attributes[i] = _attributes[i]; - buildSemanticMap(); - } -} - - -Mesh::VertexDescription::VertexDescription(const VertexDescription& desc) : - stride(desc.stride), - nAttributes(desc.nAttributes), - attributes(NULL) -{ - if (nAttributes != 0) - { - attributes = new VertexAttribute[nAttributes]; - for (uint32 i = 0; i < nAttributes; i++) - attributes[i] = desc.attributes[i]; - buildSemanticMap(); - } -} - - -Mesh::VertexDescription& -Mesh::VertexDescription::operator=(const Mesh::VertexDescription& desc) -{ - if (nAttributes < desc.nAttributes) - { - if (attributes != NULL) - delete[] attributes; - attributes = new VertexAttribute[desc.nAttributes]; - } - - nAttributes = desc.nAttributes; - stride = desc.stride; - for (uint32 i = 0; i < nAttributes; i++) - attributes[i] = desc.attributes[i]; - clearSemanticMap(); - buildSemanticMap(); - - return *this; -} - - -// TODO: This should be called in the constructor; we should start using -// exceptions in Celestia. -bool -Mesh::VertexDescription::validate() const -{ - for (uint32 i = 0; i < nAttributes; i++) - { - VertexAttribute& attr = attributes[i]; - - // Validate the attribute - if (attr.semantic >= SemanticMax || attr.format >= FormatMax) - return false; - if (attr.offset % 4 != 0) - return false; - if (attr.offset + VertexAttributeFormatSizes[attr.format] > stride) - return false; - // TODO: check for repetition of attributes - // if (vertexAttributeMap[attr->semantic].format != InvalidFormat) - // return false; - } - - return true; -} - - -Mesh::VertexDescription::~VertexDescription() -{ - delete[] attributes; -} - - -void -Mesh::VertexDescription::buildSemanticMap() -{ - for (uint32 i = 0; i < nAttributes; i++) - semanticMap[attributes[i].semantic] = attributes[i]; -} - - -void -Mesh::VertexDescription::clearSemanticMap() -{ - for (uint32 i = 0; i < SemanticMax; i++) - semanticMap[i] = VertexAttribute(); -} - - -Mesh::PrimitiveGroup::PrimitiveGroup() -{ -} - - -Mesh::PrimitiveGroup::~PrimitiveGroup() -{ - // TODO: probably should free index list; need to sort out - // ownership issues. -} - - -uint32 -Mesh::PrimitiveGroup::getPrimitiveCount() const -{ - switch (prim) - { - case TriList: - return nIndices / 3; - case TriStrip: - case TriFan: - return nIndices - 2; - case LineList: - return nIndices / 2; - case LineStrip: - return nIndices - 2; - case PointList: - case SpriteList: - return nIndices; - default: - // Invalid value - return 0; - } -} - - -Mesh::Mesh() : - vertexDesc(0, 0, NULL), - nVertices(0), - vertices(NULL), - vbObject(0), - vbInitialized(false) -{ -} - - -Mesh::~Mesh() -{ - for (vector::iterator iter = groups.begin(); - iter != groups.end(); iter++) - { - delete *iter; - } - - // TODO: this is just to cast away void* and shut up GCC warnings; - // should probably be static_cast - if (vertices != NULL) - delete[] static_cast(vertices); - - if (vbObject != 0) - { - glDeleteBuffersARB(1, &vbObject); - } -} - - -void -Mesh::setVertices(uint32 _nVertices, void* vertexData) -{ - nVertices = _nVertices; - vertices = vertexData; -} - - -bool -Mesh::setVertexDescription(const VertexDescription& desc) -{ - if (!desc.validate()) - return false; - - vertexDesc = desc; - - return true; -} - - -const Mesh::VertexDescription& Mesh::getVertexDescription() const -{ - return vertexDesc; -} - - -const Mesh::PrimitiveGroup* -Mesh::getGroup(uint32 index) const -{ - if (index >= groups.size()) - return NULL; - else - return groups[index]; -} - - -uint32 -Mesh::addGroup(PrimitiveGroup* group) -{ - groups.push_back(group); - return groups.size(); -} - - -uint32 -Mesh::addGroup(PrimitiveGroupType prim, - uint32 materialIndex, - uint32 nIndices, - uint32* indices) -{ - PrimitiveGroup* g = new PrimitiveGroup(); - g->prim = prim; - g->materialIndex = materialIndex; - g->nIndices = nIndices; - g->indices = indices; - - return addGroup(g); -} - - -uint32 -Mesh::getGroupCount() const -{ - return groups.size(); -} - - -void -Mesh::clearGroups() -{ - for (vector::iterator iter = groups.begin(); - iter != groups.end(); iter++) - { - delete *iter; - } - - groups.clear(); -} - - -const string& -Mesh::getName() const -{ - return name; -} - - -void -Mesh::setName(const string& _name) -{ - name = _name; -} - - -void -Mesh::remapIndices(const vector& indexMap) -{ - for (vector::iterator iter = groups.begin(); - iter != groups.end(); iter++) - { - PrimitiveGroup* group = *iter; - for (uint32 i = 0; i < group->nIndices; i++) - { - group->indices[i] = indexMap[group->indices[i]]; - } - } -} - - -void -Mesh::remapMaterials(const vector& materialMap) -{ - for (vector::iterator iter = groups.begin(); - iter != groups.end(); iter++) - { - (*iter)->materialIndex = materialMap[(*iter)->materialIndex]; - } -} - - -class PrimitiveGroupComparator : public std::binary_function -{ -public: - bool operator()(const Mesh::PrimitiveGroup* g0, const Mesh::PrimitiveGroup* g1) const - { - return g0->materialIndex < g1->materialIndex; - } - -private: - int unused; -}; - - -void -Mesh::aggregateByMaterial() -{ - sort(groups.begin(), groups.end(), PrimitiveGroupComparator()); -} - - -bool -Mesh::pick(const Ray3d& ray, double& distance) const -{ - double maxDistance = 1.0e30; - double closest = maxDistance; - - // Pick will automatically fail without vertex positions--no reasonable - // mesh should lack these. - if (vertexDesc.getAttribute(Position).semantic != Position || - vertexDesc.getAttribute(Position).format != Float3) - { - return false; - } - - uint posOffset = vertexDesc.getAttribute(Position).offset; - char* vdata = reinterpret_cast(vertices); - - // Iterate over all primitive groups in the mesh - for (vector::const_iterator iter = groups.begin(); - iter != groups.end(); iter++) - { - Mesh::PrimitiveGroupType primType = (*iter)->prim; - uint32 nIndices = (*iter)->nIndices; - - // Only attempt to compute the intersection of the ray with triangle - // groups. - if ((primType == TriList || primType == TriStrip || primType == TriFan) && - (nIndices >= 3) && - !(primType == TriList && nIndices % 3 != 0)) - { - uint32 index = 0; - uint32 i0 = (*iter)->indices[0]; - uint32 i1 = (*iter)->indices[1]; - uint32 i2 = (*iter)->indices[2]; - - // Iterate over the triangles in the primitive group - do - { - // Get the triangle vertices v0, v1, and v2 - Vector3d v0 = Map(reinterpret_cast(vdata + i0 * vertexDesc.stride + posOffset)).cast(); - Vector3d v1 = Map(reinterpret_cast(vdata + i1 * vertexDesc.stride + posOffset)).cast(); - Vector3d v2 = Map(reinterpret_cast(vdata + i2 * vertexDesc.stride + posOffset)).cast(); - - // Compute the edge vectors e0 and e1, and the normal n - Vector3d e0 = v1 - v0; - Vector3d e1 = v2 - v0; - Vector3d n = e0.cross(e1); - - // c is the cosine of the angle between the ray and triangle normal - double c = n.dot(ray.direction); - - // If the ray is parallel to the triangle, it either misses the - // triangle completely, or is contained in the triangle's plane. - // If it's contained in the plane, we'll still call it a miss. - if (c != 0.0) - { - double t = (n.dot(v0 - ray.origin)) / c; - if (t < closest && t > 0.0) - { - double m00 = e0.dot(e0); - double m01 = e0.dot(e1); - double m10 = e1.dot(e0); - double m11 = e1.dot(e1); - double det = m00 * m11 - m01 * m10; - if (det != 0.0) - { - Vector3d p = ray.point(t); - Vector3d q = p - v0; - double q0 = e0.dot(q); - double q1 = e1.dot(q); - double d = 1.0 / det; - double s0 = (m11 * q0 - m01 * q1) * d; - double s1 = (m00 * q1 - m10 * q0) * d; - if (s0 >= 0.0 && s1 >= 0.0 && s0 + s1 <= 1.0) - closest = t; - } - } - } - - // Get the indices for the next triangle - if (primType == TriList) - { - index += 3; - if (index < nIndices) - { - i0 = (*iter)->indices[index + 0]; - i1 = (*iter)->indices[index + 1]; - i2 = (*iter)->indices[index + 2]; - } - } - else if (primType == TriStrip) - { - index += 1; - if (index < nIndices) - { - i0 = i1; - i1 = i2; - i2 = (*iter)->indices[index]; - // TODO: alternate orientation of triangles in a strip - } - } - else // primType == TriFan - { - index += 1; - if (index < nIndices) - { - index += 1; - i1 = i2; - i2 = (*iter)->indices[index]; - } - } - - } while (index < nIndices); - } - } - - if (closest != maxDistance) - { - distance = closest; - return true; - } - else - { - return false; - } -} - - -void -Mesh::render(const std::vector& materials, - RenderContext& rc) const -{ - // 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 (!vbInitialized && isVBOSupported()) - { - vbInitialized = true; - - if (nVertices * vertexDesc.stride > MinVBOSize) - { - glGenBuffersARB(1, &vbObject); - if (vbObject != 0) - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbObject); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, - nVertices * vertexDesc.stride, - vertices, - GL_STATIC_DRAW_ARB); - } - } - } - - if (vbObject != 0) - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbObject); - rc.setVertexArrays(vertexDesc, NULL); - } - else - { - rc.setVertexArrays(vertexDesc, vertices); - } - - uint32 lastMaterial = ~0u; - - // Iterate over all primitive groups in the mesh - for (vector::const_iterator iter = groups.begin(); - iter != groups.end(); iter++) - { - // Set up the material - const Material* mat = NULL; - uint32 materialIndex = (*iter)->materialIndex; - if (materialIndex != lastMaterial && materialIndex < materials.size()) - mat = materials[materialIndex]; - - rc.setMaterial(mat); - rc.drawGroup(**iter); - } - - if (vbObject != 0) - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); -} - - -AlignedBox -Mesh::getBoundingBox() const -{ - AlignedBox bbox; - - // Return an empty box if there's no position info - if (vertexDesc.getAttribute(Position).format != Float3) - return bbox; - - char* vdata = reinterpret_cast(vertices) + vertexDesc.getAttribute(Position).offset; - - if (vertexDesc.getAttribute(PointSize).format == Float1) - { - // Handle bounding box calculation for point sprites. Unlike other - // primitives, point sprite vertices have a non-zero size. - int pointSizeOffset = (int) vertexDesc.getAttribute(PointSize).offset - - (int) vertexDesc.getAttribute(Position).offset; - - for (uint32 i = 0; i < nVertices; i++, vdata += vertexDesc.stride) - { - Vector3f center = Map(reinterpret_cast(vdata)); - float pointSize = (reinterpret_cast(vdata + pointSizeOffset))[0]; - Vector3f offsetVec = Vector3f::Constant(pointSize); - - AlignedBox pointbox(center - offsetVec, center + offsetVec); - bbox.extend(pointbox); - } - } - else - { - for (uint32 i = 0; i < nVertices; i++, vdata += vertexDesc.stride) - bbox.extend(Map(reinterpret_cast(vdata))); - } - - return bbox; -} - - -void -Mesh::transform(const Vector3f& translation, float scale) -{ - if (vertexDesc.getAttribute(Position).format != Float3) - return; - - char* vdata = reinterpret_cast(vertices) + vertexDesc.getAttribute(Position).offset; - uint32 i; - - // Scale and translate the vertex positions - for (i = 0; i < nVertices; i++, vdata += vertexDesc.stride) - { - const Vector3f tv = (Map(reinterpret_cast(vdata)) + translation) * scale; - Map(reinterpret_cast(vdata)) = tv; -#if CELVEC - reinterpret_cast(vdata)[0] = tv.x(); - reinterpret_cast(vdata)[1] = tv.y(); - reinterpret_cast(vdata)[2] = tv.z(); -#endif - } - - // Point sizes need to be scaled as well - if (vertexDesc.getAttribute(PointSize).format == Float1) - { - vdata = reinterpret_cast(vertices) + vertexDesc.getAttribute(PointSize).offset; - for (i = 0; i < nVertices; i++, vdata += vertexDesc.stride) - reinterpret_cast(vdata)[0] *= scale; - } -} - - -uint32 -Mesh::getPrimitiveCount() const -{ - uint32 count = 0; - - for (vector::const_iterator iter = groups.begin(); - iter != groups.end(); iter++) - { - count += (*iter)->getPrimitiveCount(); - } - - return count; -} - - -Mesh::PrimitiveGroupType -Mesh::parsePrimitiveGroupType(const string& name) -{ - if (name == "trilist") - return TriList; - else if (name == "tristrip") - return TriStrip; - else if (name == "trifan") - return TriFan; - else if (name == "linelist") - return LineList; - else if (name == "linestrip") - return LineStrip; - else if (name == "points") - return PointList; - else if (name == "sprites") - return SpriteList; - else - return InvalidPrimitiveGroupType; -} - - -Mesh::VertexAttributeSemantic -Mesh::parseVertexAttributeSemantic(const string& name) -{ - if (name == "position") - return Position; - else if (name == "normal") - return Normal; - else if (name == "color0") - return Color0; - else if (name == "color1") - return Color1; - else if (name == "tangent") - return Tangent; - else if (name == "texcoord0") - return Texture0; - else if (name == "texcoord1") - return Texture1; - else if (name == "texcoord2") - return Texture2; - else if (name == "texcoord3") - return Texture3; - else if (name == "pointsize") - return PointSize; - else - return InvalidSemantic; -} - - -Mesh::VertexAttributeFormat -Mesh::parseVertexAttributeFormat(const string& name) -{ - if (name == "f1") - return Float1; - else if (name == "f2") - return Float2; - else if (name == "f3") - return Float3; - else if (name == "f4") - return Float4; - else if (name == "ub4") - return UByte4; - else - return InvalidFormat; -} - - -Mesh::TextureSemantic -Mesh::parseTextureSemantic(const string& name) -{ - if (name == "texture0") - return DiffuseMap; - else if (name == "normalmap") - return NormalMap; - else if (name == "specularmap") - return SpecularMap; - else if (name == "emissivemap") - return EmissiveMap; - else - return InvalidTextureSemantic; -} - - -uint32 -Mesh::getVertexAttributeSize(VertexAttributeFormat fmt) -{ - switch (fmt) - { - case Float1: - case UByte4: - return 4; - case Float2: - return 8; - case Float3: - return 12; - case Float4: - return 16; - default: - return 0; - } -} Index: src/celengine/rendcontext.cpp =================================================================== --- src/celengine/rendcontext.cpp (revision 4952) +++ src/celengine/rendcontext.cpp (working copy) @@ -11,17 +11,18 @@ #include #include "rendcontext.h" #include "texmanager.h" +#include "modelgeometry.h" #include "body.h" #include #include "vecgl.h" #include - +using namespace cmod; using namespace Eigen; using namespace std; -static Mesh::Material defaultMaterial; +static Material defaultMaterial; static GLenum GLPrimitiveModes[Mesh::PrimitiveTypeMax] = { @@ -61,12 +62,27 @@ static void setStandardVertexArrays(const Mesh::VertexDescription& desc, - void* vertexData); + const void* vertexData); static void setExtendedVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData); +static ResourceHandle +GetTextureHandle(Material::TextureResource* texResource) +{ + CelestiaTextureResource* t = reinterpret_cast(texResource); + if (t) + { + return t->textureHandle(); + } + else + { + return InvalidResource; + } +} + + RenderContext::RenderContext() : material(&defaultMaterial), locked(false), @@ -80,7 +96,7 @@ } -RenderContext::RenderContext(const Mesh::Material* _material) +RenderContext::RenderContext(const Material* _material) { if (_material == NULL) material = &defaultMaterial; @@ -89,7 +105,7 @@ } -const Mesh::Material* +const Material* RenderContext::getMaterial() const { return material; @@ -97,7 +113,7 @@ void -RenderContext::setMaterial(const Mesh::Material* newMaterial) +RenderContext::setMaterial(const Material* newMaterial) { if (!locked) { @@ -114,8 +130,8 @@ } else if (renderPass == EmissivePass) { - if (material->maps[Mesh::EmissiveMap] != - newMaterial->maps[Mesh::EmissiveMap]) + if (material->maps[Material::EmissiveMap] != + newMaterial->maps[Material::EmissiveMap]) { material = newMaterial; makeCurrent(*material); @@ -158,8 +174,9 @@ { // Skip rendering if this is the emissive pass but there's no // emissive texture. - if (renderPass == EmissivePass && - material->maps[Mesh::EmissiveMap] == InvalidResource) + ResourceHandle emissiveMap = GetTextureHandle(material->maps[Material::EmissiveMap]); + + if (renderPass == EmissivePass && emissiveMap == InvalidResource) { return; } @@ -187,16 +204,16 @@ FixedFunctionRenderContext::FixedFunctionRenderContext() : RenderContext(), - blendMode(Mesh::InvalidBlend), + blendMode(Material::InvalidBlend), specularOn(false), lightingEnabled(true) { } -FixedFunctionRenderContext::FixedFunctionRenderContext(const Mesh::Material* _material) : +FixedFunctionRenderContext::FixedFunctionRenderContext(const Material* _material) : RenderContext(_material), - blendMode(Mesh::InvalidBlend), + blendMode(Material::InvalidBlend), specularOn(false), lightingEnabled(true) { @@ -213,14 +230,19 @@ void -FixedFunctionRenderContext::makeCurrent(const Mesh::Material& m) +FixedFunctionRenderContext::makeCurrent(const Material& m) { if (getRenderPass() == PrimaryPass) { Texture* t = NULL; - if (m.maps[Mesh::DiffuseMap] != InvalidResource && useTexCoords) - t = GetTextureManager()->find(m.maps[Mesh::DiffuseMap]); + ResourceHandle diffuseMap = GetTextureHandle(getMaterial()->maps[Material::DiffuseMap]); + + if (diffuseMap != InvalidResource && useTexCoords) + { + t = GetTextureManager()->find(diffuseMap); + } + if (t == NULL) { glDisable(GL_TEXTURE_2D); @@ -231,9 +253,9 @@ t->bind(); } - Mesh::BlendMode newBlendMode = Mesh::InvalidBlend; + Material::BlendMode newBlendMode = Material::InvalidBlend; if (m.opacity != 1.0f || - m.blend == Mesh::AdditiveBlend || + m.blend == Material::AdditiveBlend || (t != NULL && t->hasAlpha())) { newBlendMode = m.blend; @@ -244,17 +266,17 @@ blendMode = newBlendMode; switch (blendMode) { - case Mesh::NormalBlend: + case Material::NormalBlend: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(GL_FALSE); break; - case Mesh::AdditiveBlend: + case Material::AdditiveBlend: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glDepthMask(GL_FALSE); break; - case Mesh::PremultipliedAlphaBlend: + case Material::PremultipliedAlphaBlend: glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(GL_FALSE); @@ -280,7 +302,7 @@ m.opacity); #endif - if (m.specular == Color::Black) + if (m.specular == Material::Color(0.0f, 0.0f, 0.0f)) { float matSpecular[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; float zero = 0.0f; @@ -337,8 +359,11 @@ else if (getRenderPass() == EmissivePass) { Texture* t = NULL; - if (m.maps[Mesh::EmissiveMap] != InvalidResource && useTexCoords) - t = GetTextureManager()->find(m.maps[Mesh::EmissiveMap]); + ResourceHandle emissiveMap = GetTextureHandle(m.maps[Material::EmissiveMap]); + if (emissiveMap != InvalidResource && useTexCoords) + { + t = GetTextureManager()->find(emissiveMap); + } if (t == NULL) { @@ -354,7 +379,7 @@ void -FixedFunctionRenderContext::setVertexArrays(const Mesh::VertexDescription& desc, void* vertexData) +FixedFunctionRenderContext::setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData) { // Update the material if normals appear or disappear in the vertex // description. @@ -389,7 +414,7 @@ void -VP_Combiner_RenderContext::setVertexArrays(const Mesh::VertexDescription& desc, void* vertexData) +VP_Combiner_RenderContext::setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData) { setStandardVertexArrays(desc, vertexData); setExtendedVertexArrays(desc, vertexData); @@ -397,7 +422,7 @@ void -VP_FP_RenderContext::setVertexArrays(const Mesh::VertexDescription& desc, void* vertexData) +VP_FP_RenderContext::setVertexArrays(const Mesh::VertexDescription& desc, const void* vertexData) { setStandardVertexArrays(desc, vertexData); setExtendedVertexArrays(desc, vertexData); @@ -408,7 +433,7 @@ void setStandardVertexArrays(const Mesh::VertexDescription& desc, - void* vertexData) + const void* vertexData) { const Mesh::VertexAttribute& position = desc.getAttribute(Mesh::Position); const Mesh::VertexAttribute& normal = desc.getAttribute(Mesh::Normal); @@ -422,7 +447,7 @@ // Set up the vertex arrays glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, desc.stride, - reinterpret_cast(vertexData) + position.offset); + reinterpret_cast(vertexData) + position.offset); // Set up the normal array switch (normal.format) @@ -431,7 +456,7 @@ glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GLComponentTypes[(int) normal.format], desc.stride, - reinterpret_cast(vertexData) + normal.offset); + reinterpret_cast(vertexData) + normal.offset); break; default: glDisableClientState(GL_NORMAL_ARRAY); @@ -448,7 +473,7 @@ glColorPointer(GLComponentCounts[color0.format], GLComponentTypes[color0.format], desc.stride, - reinterpret_cast(vertexData) + color0.offset); + reinterpret_cast(vertexData) + color0.offset); break; default: glDisableClientState(GL_COLOR_ARRAY); @@ -466,7 +491,7 @@ glTexCoordPointer(GLComponentCounts[(int) texCoord0.format], GLComponentTypes[(int) texCoord0.format], desc.stride, - reinterpret_cast(vertexData) + texCoord0.offset); + reinterpret_cast(vertexData) + texCoord0.offset); break; default: glDisableClientState(GL_TEXTURE_COORD_ARRAY); @@ -522,7 +547,7 @@ GLSL_RenderContext::GLSL_RenderContext(const LightingState& ls, float _objRadius, const Quaternionf& orientation) : lightingState(ls), atmosphere(NULL), - blendMode(Mesh::InvalidBlend), + blendMode(Material::InvalidBlend), objRadius(_objRadius), objOrientation(orientation), lunarLambert(0.0f) @@ -566,7 +591,7 @@ } void -GLSL_RenderContext::makeCurrent(const Mesh::Material& m) +GLSL_RenderContext::makeCurrent(const Material& m) { Texture* textures[4] = { NULL, NULL, NULL, NULL }; unsigned int nTextures = 0; @@ -599,9 +624,14 @@ shaderProps.lightModel = ShaderProperties::ParticleDiffuseModel; } - if (m.maps[Mesh::DiffuseMap] != InvalidResource && (useTexCoords || usePointSize)) + ResourceHandle diffuseMap = GetTextureHandle(m.maps[Material::DiffuseMap]); + ResourceHandle normalMap = GetTextureHandle(m.maps[Material::NormalMap]); + ResourceHandle specularMap = GetTextureHandle(m.maps[Material::SpecularMap]); + ResourceHandle emissiveMap = GetTextureHandle(m.maps[Material::EmissiveMap]); + + if (diffuseMap != InvalidResource && (useTexCoords || usePointSize)) { - baseTex = GetTextureManager()->find(m.maps[Mesh::DiffuseMap]); + baseTex = GetTextureManager()->find(diffuseMap); if (baseTex != NULL) { shaderProps.texUsage |= ShaderProperties::DiffuseTexture; @@ -609,9 +639,9 @@ } } - if (m.maps[Mesh::NormalMap] != InvalidResource) + if (normalMap != InvalidResource) { - bumpTex = GetTextureManager()->find(m.maps[Mesh::NormalMap]); + bumpTex = GetTextureManager()->find(normalMap); if (bumpTex != NULL) { shaderProps.texUsage |= ShaderProperties::NormalTexture; @@ -623,10 +653,10 @@ } } - if (m.specular != Color::Black && useNormals) + if (m.specular != Material::Color(0.0f, 0.0f, 0.0f) && useNormals) { shaderProps.lightModel = ShaderProperties::PerPixelSpecularModel; - specTex = GetTextureManager()->find(m.maps[Mesh::SpecularMap]); + specTex = GetTextureManager()->find(specularMap); if (specTex == NULL) { if (baseTex != NULL) @@ -639,9 +669,9 @@ } } - if (m.maps[Mesh::EmissiveMap] != InvalidResource) + if (emissiveMap != InvalidResource) { - emissiveTex = GetTextureManager()->find(m.maps[Mesh::EmissiveMap]); + emissiveTex = GetTextureManager()->find(emissiveMap); if (emissiveTex != NULL) { shaderProps.texUsage |= ShaderProperties::EmissiveTexture; @@ -713,8 +743,10 @@ #else Color diffuse(m.diffuse.red(), m.diffuse.green(), m.diffuse.blue(), m.opacity); #endif + Color specular(m.specular.red(), m.specular.green(), m.specular.blue()); + Color emissive(m.emissive.red(), m.emissive.green(), m.emissive.blue()); - prog->setLightParameters(lightingState, diffuse, m.specular, m.emissive); + prog->setLightParameters(lightingState, diffuse, specular, emissive); if (shaderProps.hasEclipseShadows() != 0) prog->setEclipseShadowParameters(lightingState, objRadius, objOrientation); @@ -764,9 +796,9 @@ } } - Mesh::BlendMode newBlendMode = Mesh::InvalidBlend; + Material::BlendMode newBlendMode = Material::InvalidBlend; if (m.opacity != 1.0f || - m.blend == Mesh::AdditiveBlend || + m.blend == Material::AdditiveBlend || (baseTex != NULL && baseTex->hasAlpha())) { newBlendMode = m.blend; @@ -777,17 +809,17 @@ blendMode = newBlendMode; switch (blendMode) { - case Mesh::NormalBlend: + case Material::NormalBlend: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(disableDepthWriteOnBlend ? GL_FALSE : GL_TRUE); break; - case Mesh::AdditiveBlend: + case Material::AdditiveBlend: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glDepthMask(disableDepthWriteOnBlend ? GL_FALSE : GL_TRUE); break; - case Mesh::PremultipliedAlphaBlend: + case Material::PremultipliedAlphaBlend: glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(disableDepthWriteOnBlend ? GL_FALSE : GL_TRUE); @@ -803,7 +835,7 @@ void GLSL_RenderContext::setVertexArrays(const Mesh::VertexDescription& desc, - void* vertexData) + const void* vertexData) { setStandardVertexArrays(desc, vertexData); setExtendedVertexArrays(desc, vertexData); @@ -849,7 +881,7 @@ /***** GLSL-Unlit render context ******/ GLSLUnlit_RenderContext::GLSLUnlit_RenderContext(float _objRadius) : - blendMode(Mesh::InvalidBlend), + blendMode(Material::InvalidBlend), objRadius(_objRadius) { initLightingEnvironment(); @@ -877,7 +909,7 @@ void -GLSLUnlit_RenderContext::makeCurrent(const Mesh::Material& m) +GLSLUnlit_RenderContext::makeCurrent(const Material& m) { Texture* textures[4] = { NULL, NULL, NULL, NULL }; unsigned int nTextures = 0; @@ -888,9 +920,10 @@ shaderProps.lightModel = ShaderProperties::EmissiveModel; shaderProps.texUsage = ShaderProperties::SharedTextureCoords; - if (m.maps[Mesh::DiffuseMap] != InvalidResource && (useTexCoords || usePointSize)) + ResourceHandle diffuseMap = GetTextureHandle(m.maps[Material::DiffuseMap]); + if (diffuseMap != InvalidResource && (useTexCoords || usePointSize)) { - baseTex = GetTextureManager()->find(m.maps[Mesh::DiffuseMap]); + baseTex = GetTextureManager()->find(diffuseMap); if (baseTex != NULL) { shaderProps.texUsage |= ShaderProperties::DiffuseTexture; @@ -929,9 +962,9 @@ prog->pointScale = getPointScale(); } - Mesh::BlendMode newBlendMode = Mesh::InvalidBlend; + Material::BlendMode newBlendMode = Material::InvalidBlend; if (m.opacity != 1.0f || - m.blend == Mesh::AdditiveBlend || + m.blend == Material::AdditiveBlend || (baseTex != NULL && baseTex->hasAlpha())) { newBlendMode = m.blend; @@ -942,17 +975,17 @@ blendMode = newBlendMode; switch (blendMode) { - case Mesh::NormalBlend: + case Material::NormalBlend: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(GL_FALSE); break; - case Mesh::AdditiveBlend: + case Material::AdditiveBlend: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glDepthMask(GL_FALSE); break; - case Mesh::PremultipliedAlphaBlend: + case Material::PremultipliedAlphaBlend: glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(GL_FALSE); @@ -968,7 +1001,7 @@ void GLSLUnlit_RenderContext::setVertexArrays(const Mesh::VertexDescription& desc, - void* vertexData) + const void* vertexData) { setStandardVertexArrays(desc, vertexData); setExtendedVertexArrays(desc, vertexData); Index: src/celengine/body.cpp =================================================================== --- src/celengine/body.cpp (revision 4952) +++ src/celengine/body.cpp (working copy) @@ -13,7 +13,7 @@ #include #include #include -#include "mesh.h" +#include "geometry.h" #include "meshmanager.h" #include "body.h" #include "atmosphere.h" Index: src/celengine/renderglsl.cpp =================================================================== --- src/celengine/renderglsl.cpp (revision 4952) +++ src/celengine/renderglsl.cpp (working copy) @@ -27,13 +27,14 @@ #include "shadermanager.h" #include "spheremesh.h" #include "lodspheremesh.h" -#include "model.h" +#include "geometry.h" #include "regcombine.h" #include "vertexprog.h" #include "texmanager.h" #include "meshmanager.h" #include "renderinfo.h" #include "renderglsl.h" +#include "modelgeometry.h" #include "vecgl.h" #include #include @@ -42,7 +43,7 @@ #include #include - +using namespace cmod; using namespace Eigen; using namespace std; @@ -319,14 +320,17 @@ // override all materials specified in the geometry file. if (texOverride != InvalidResource) { - Mesh::Material m; - m.diffuse = ri.color; - m.specular = ri.specularColor; + Material m; + m.diffuse = Material::Color(ri.color.red(), ri.color.green(), ri.color.blue()); + m.specular = Material::Color(ri.specularColor.red(), ri.specularColor.green(), ri.specularColor.blue()); m.specularPower = ri.specularPower; - m.maps[Mesh::DiffuseMap] = texOverride; + + CelestiaTextureResource textureResource(texOverride); + m.maps[Material::DiffuseMap] = &textureResource; rc.setMaterial(&m); rc.lock(); geometry->render(rc, tsec); + m.maps[Material::DiffuseMap] = NULL; // prevent Material destructor from deleting the texture resource } else { @@ -359,14 +363,17 @@ // override all materials specified in the model file. if (texOverride != InvalidResource) { - Mesh::Material m; - m.diffuse = ri.color; - m.specular = ri.specularColor; + Material m; + m.diffuse = Material::Color(ri.color.red(), ri.color.green(), ri.color.blue()); + m.specular = Material::Color(ri.specularColor.red(), ri.specularColor.green(), ri.specularColor.blue()); m.specularPower = ri.specularPower; - m.maps[Mesh::DiffuseMap] = texOverride; + + CelestiaTextureResource textureResource(texOverride); + m.maps[Material::DiffuseMap] = &textureResource; rc.setMaterial(&m); rc.lock(); geometry->render(rc, tsec); + m.maps[Material::DiffuseMap] = NULL; // prevent Material destructor from deleting the texture resource } else { @@ -725,3 +732,238 @@ glUseProgramObjectARB(0); } + + + +/*! Render a mesh object + * Parameters: + * tsec : animation clock time in seconds + */ +void renderGeometryShadow_GLSL(Geometry* geometry, + FramebufferObject* shadowFbo, + const RenderInfo& ri, + const LightingState& ls, + float geometryScale, + const Quaternionf& planetOrientation, + double tsec) +{ + glDisable(GL_LIGHTING); + + shadowFbo->bind(); + glViewport(0, 0, shadowFbo->width(), shadowFbo->height()); + glClear(GL_DEPTH_BUFFER_BIT); + + // Write only to the depth buffer + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glDepthMask(GL_TRUE); + + // Set up the camera for drawing from the light source direction + + // Render backfaces only in order to reduce self-shadowing artifacts + glCullFace(GL_FRONT); + + GLSL_RenderContext rc(ls, geometryScale, planetOrientation); + + rc.setPointScale(ri.pointScale); + + int lightIndex = 0; + Vector3f viewDir = -ls.lights[lightIndex].direction_obj; + Vector3f upDir = viewDir.unitOrthogonal(); + Vector3f rightDir = upDir.cross(viewDir); + + + glUseProgramObjectARB(0); + + geometry->render(rc, tsec); + + shadowFbo->unbind(); + + // Re-enable the color buffer + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); +} + + + + +FramebufferObject::FramebufferObject(GLuint width, GLuint height, unsigned int attachments) : + m_width(width), + m_height(height), + m_colorTexId(0), + m_depthTexId(0), + m_fboId(0), + m_status(GL_FRAMEBUFFER_UNSUPPORTED_EXT) +{ + if (attachments != 0) + { + generateFbo(attachments); + } +} + + +FramebufferObject::~FramebufferObject() +{ + cleanup(); +} + + +bool +FramebufferObject::isValid() const +{ + return m_status == GL_FRAMEBUFFER_COMPLETE_EXT; +} + + +GLuint +FramebufferObject::colorTexture() const +{ + return m_colorTexId; +} + + +GLuint +FramebufferObject::depthTexture() const +{ + return m_depthTexId; +} + + +void +FramebufferObject::generateColorTexture() +{ + // Create and bind the texture + glGenTextures(1, &m_colorTexId); + glBindTexture(GL_TEXTURE_2D, m_colorTexId); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Clamp to edge + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + // Set the texture dimensions + // Do we need to set GL_DEPTH_COMPONENT24 here? + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m_width, m_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + + // Unbind the texture + glBindTexture(GL_TEXTURE_2D, 0); +} + + +void +FramebufferObject::generateDepthTexture() +{ + // Create and bind the texture + glGenTextures(1, &m_depthTexId); + glBindTexture(GL_TEXTURE_2D, m_depthTexId); + + // Only nearest sampling is appropriate for depth textures + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // Clamp to edge + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + // Set the texture dimensions + // Do we need to set GL_DEPTH_COMPONENT24 here? + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, m_width, m_height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + + // Unbind the texture + glBindTexture(GL_TEXTURE_2D, 0); +} + + +void +FramebufferObject::generateFbo(unsigned int attachments) +{ + // Create the FBO + glGenFramebuffersEXT(1, &m_fboId); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId); + + glReadBuffer(GL_NONE); + + if ((attachments & ColorAttachment) != 0) + { + generateColorTexture(); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_colorTexId, 0); + m_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (m_status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + cleanup(); + return; + } + } + else + { + // Depth-only rendering; no color buffer. + glDrawBuffer(GL_NONE); + } + + if ((attachments & DepthAttachment) != 0) + { + generateDepthTexture(); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_depthTexId, 0); + m_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (m_status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + cleanup(); + return; + } + } + else + { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0); + } + + // Restore default frame buffer + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +} + + +// Delete all GL objects associated with this framebuffer object +void +FramebufferObject::cleanup() +{ + if (m_fboId != 0) + { + glDeleteFramebuffersEXT(1, &m_fboId); + } + + if (m_colorTexId != 0) + { + glDeleteTextures(1, &m_colorTexId); + } + + if (m_depthTexId != 0) + { + glDeleteTextures(1, &m_depthTexId); + } +} + + +bool +FramebufferObject::bind() +{ + if (isValid()) + { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId); + return true; + } + else + { + return false; + } +} + + +bool +FramebufferObject::unbind() +{ + // Restore default frame buffer + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + return true; +} + Index: src/celengine/model.h =================================================================== --- src/celengine/model.h (revision 4952) +++ src/celengine/model.h (working copy) @@ -1,190 +0,0 @@ -// model.h -// -// Copyright (C) 2004-2006, Chris Laurel -// -// 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. - -#ifndef _CELENGINE_MODEL_H_ -#define _CELENGINE_MODEL_H_ - -#include "mesh.h" - -class Geometry -{ -public: - Geometry() {}; - virtual ~Geometry() {}; - - //! Render the geometry in the specified OpenGL context - virtual void render(RenderContext& rc, double t = 0.0) = 0; - - /*! Find the closest intersection between the ray and the - * model. If the ray intersects the model, return true - * and set distance; otherwise return false and leave - * distance unmodified. - */ - virtual bool pick(const Ray3d& r, double& distance) const = 0; - - virtual bool isOpaque() const = 0; - - virtual bool isNormalized() const - { - return true; - } - - /*! Return true if the specified texture map type is used at - * all within this geometry object. This information is used - * to decide whether multiple rendering passes are required. - */ - virtual bool usesTextureType(Mesh::TextureSemantic) const - { - return false; - } - - /*! Load all textures used by the model. */ - virtual void loadTextures() - { - } -}; - - -/*! - * Model is the standard geometry object in Celestia. A Model - * consists of a library of materials together with a list of - * meshes. Each mesh object contains a pool of vertices and a - * set of primitive groups. A primitive groups consists of a - * a primitive group type and a list of vertex indices. This - * structure is exactly the one used in Celestia model (.cmod) - * files. - */ -class Model : public Geometry -{ - public: - Model(); - ~Model(); - - /*! Return the material with the specified index, or NULL if - * the index is out of range. - */ - const Mesh::Material* getMaterial(uint32) const; - - /*! Add a new material to the model's material library; the - * return value is the number of materials in the model. - */ - uint32 addMaterial(const Mesh::Material*); - - /*! Return the number of materials in the model - */ - uint32 getMaterialCount() const; - - /*! Return the total number of vertices in the model - */ - uint32 getVertexCount() const; - - /*! Return the total number of primitives in the model - */ - uint32 getPrimitiveCount() const; - - /*! Return the mesh with the specified index, or NULL if the - * index is out of range. - */ - Mesh* getMesh(uint32) const; - - /*! Add a new mesh to the model; the return value is the - * total number of meshes in the model. - */ - uint32 addMesh(Mesh*); - - /*! Find the closest intersection between the ray and the - * model. If the ray intersects the model, return true - * and set distance; otherwise return false and leave - * distance unmodified. - */ - virtual bool pick(const Ray3d& r, double& distance) const; - - //! Render the model in the current OpenGL context - virtual void render(RenderContext&, double t = 0.0); - - void transform(const Eigen::Vector3f& translation, float scale); - - /*! Apply a uniform scale to the model so that it fits into - * a box with a center at centerOffset and a maximum side - * length of one. - */ - void normalize(const Eigen::Vector3f& centerOffset); - - /*! Return true if the specified texture map type is used at - * all within a mesh. This information is used to decide - * if multiple rendering passes are required. - */ - virtual bool usesTextureType(Mesh::TextureSemantic) const; - - /*! Return true if the model has no translucent components. */ - virtual bool isOpaque() const - { - return opaque; - } - - virtual bool isNormalized() const - { - return normalized; - } - - /*! Set the opacity flag based on material usage within the model */ - void determineOpacity(); - - - class MeshComparator - { - public: - virtual ~MeshComparator() {}; - - virtual bool operator()(const Mesh&, const Mesh&) const = 0; - }; - - /*! Sort the model's meshes in place. */ - void sortMeshes(const MeshComparator&); - - /*! Optimize the model by eliminating all duplicated materials */ - void uniquifyMaterials(); - - void loadTextures(); - - /*! This comparator will roughly sort the model's meshes by - * opacity so that transparent meshes are rendered last. It's far - * from perfect, but covers a lot of cases. A better method of - * opacity sorting would operate at the primitive group level, or - * even better at the triangle level. - * - * Standard usage for this class is: - * model->sortMeshes(Model::OpacityComparator()); - * - * uniquifyMaterials() should be used before sortMeshes(), since - * the opacity comparison depends on material indices being ordered - * by opacity. - */ - class OpacityComparator : public MeshComparator - { - public: - OpacityComparator(); - virtual ~OpacityComparator() {}; - - virtual bool operator()(const Mesh&, const Mesh&) const; - - private: - int unused; - }; - - private: - std::vector materials; - std::vector meshes; - - bool textureUsage[Mesh::TextureSemanticMax]; - bool opaque; - bool normalized; -}; - -#endif // !_CELENGINE_MODEL_H_ Index: src/celengine/rendcontext.h =================================================================== --- src/celengine/rendcontext.h (revision 4952) +++ src/celengine/rendcontext.h (working copy) @@ -1,6 +1,7 @@ // rendcontext.h // -// Copyright (C) 2004-2006, Chris Laurel +// Copyright (C) 2004-2010, Celestia Development Team +// Original version by Chris Laurel // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -10,8 +11,8 @@ #ifndef _CELENGINE_RENDCONTEXT_H_ #define _CELENGINE_RENDCONTEXT_H_ -#include "mesh.h" #include "shadermanager.h" +#include #include @@ -20,17 +21,17 @@ public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW - RenderContext(const Mesh::Material*); + RenderContext(const cmod::Material*); RenderContext(); virtual ~RenderContext() {}; - virtual void makeCurrent(const Mesh::Material&) = 0; - virtual void setVertexArrays(const Mesh::VertexDescription& desc, - void* vertexData) = 0; - virtual void drawGroup(const Mesh::PrimitiveGroup& group); + virtual void makeCurrent(const cmod::Material&) = 0; + virtual void setVertexArrays(const cmod::Mesh::VertexDescription& desc, + const void* vertexData) = 0; + virtual void drawGroup(const cmod::Mesh::PrimitiveGroup& group); - const Mesh::Material* getMaterial() const; - void setMaterial(const Mesh::Material*); + const cmod::Material* getMaterial() const; + void setMaterial(const cmod::Material*); void lock() { locked = true; } void unlock() { locked = false; } bool isLocked() const { return locked; } @@ -51,7 +52,7 @@ Eigen::Quaternionf getCameraOrientation() const; private: - const Mesh::Material* material; + const cmod::Material* material; bool locked; RenderPass renderPass; float pointScale; @@ -68,17 +69,17 @@ class FixedFunctionRenderContext : public RenderContext { public: - FixedFunctionRenderContext(const Mesh::Material*); + FixedFunctionRenderContext(const cmod::Material*); FixedFunctionRenderContext(); virtual ~FixedFunctionRenderContext(); - virtual void makeCurrent(const Mesh::Material&); - virtual void setVertexArrays(const Mesh::VertexDescription& desc, - void* vertexData); + virtual void makeCurrent(const cmod::Material&); + virtual void setVertexArrays(const cmod::Mesh::VertexDescription& desc, + const void* vertexData); void setLighting(bool); private: - Mesh::BlendMode blendMode; + cmod::Material::BlendMode blendMode; bool specularOn; bool lightingEnabled; }; @@ -88,11 +89,11 @@ { public: VP_FP_RenderContext(); - VP_FP_RenderContext(const Mesh::Material*); + VP_FP_RenderContext(const cmod::Material*); - virtual void makeCurrent(const Mesh::Material&); - virtual void setVertexArrays(const Mesh::VertexDescription& desc, - void* vertexData); + virtual void makeCurrent(const cmod::Material&); + virtual void setVertexArrays(const cmod::Mesh::VertexDescription& desc, + const void* vertexData); }; @@ -100,11 +101,11 @@ { public: VP_Combiner_RenderContext(); - VP_Combiner_RenderContext(const Mesh::Material*); + VP_Combiner_RenderContext(const cmod::Material*); - virtual void makeCurrent(const Mesh::Material&); - virtual void setVertexArrays(const Mesh::VertexDescription& desc, - void* vertexData); + virtual void makeCurrent(const cmod::Material&); + virtual void setVertexArrays(const cmod::Mesh::VertexDescription& desc, + const void* vertexData); }; @@ -116,9 +117,9 @@ GLSL_RenderContext(const LightingState& ls, float _objRadius, const Eigen::Quaternionf& orientation); virtual ~GLSL_RenderContext(); - virtual void makeCurrent(const Mesh::Material&); - virtual void setVertexArrays(const Mesh::VertexDescription& desc, - void* vertexData); + virtual void makeCurrent(const cmod::Material&); + virtual void setVertexArrays(const cmod::Mesh::VertexDescription& desc, + const void* vertexData); virtual void setLunarLambert(float); virtual void setAtmosphere(const Atmosphere*); @@ -131,7 +132,7 @@ private: const LightingState& lightingState; const Atmosphere* atmosphere; - Mesh::BlendMode blendMode; + cmod::Material::BlendMode blendMode; float objRadius; Eigen::Quaternionf objOrientation; @@ -148,16 +149,16 @@ GLSLUnlit_RenderContext(float _objRadius); virtual ~GLSLUnlit_RenderContext(); - virtual void makeCurrent(const Mesh::Material&); - virtual void setVertexArrays(const Mesh::VertexDescription& desc, - void* vertexData); + virtual void makeCurrent(const cmod::Material&); + virtual void setVertexArrays(const cmod::Mesh::VertexDescription& desc, + const void* vertexData); private: - void initLightingEnvironment(); - void setLightingParameters(CelestiaGLProgram& prog, Color diffuseColor, Color specularColor); + void initLightingEnvironment(); + void setLightingParameters(CelestiaGLProgram& prog, Color diffuseColor, Color specularColor); private: - Mesh::BlendMode blendMode; + cmod::Material::BlendMode blendMode; float objRadius; ShaderProperties shaderProps; Index: src/celengine/modelfile.h =================================================================== --- src/celengine/modelfile.h (revision 4952) +++ src/celengine/modelfile.h (working copy) @@ -1,91 +0,0 @@ -// modelfile.h -// -// Copyright (C) 2004, Chris Laurel -// -// 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. - -#ifndef _CELMESH_MODELFILE_H_ -#define _CELMESH_MODELFILE_H_ - -#include "model.h" -#include -#include - -#define CEL_MODEL_HEADER_LENGTH 16 -#define CEL_MODEL_HEADER_ASCII "#celmodel__ascii" -#define CEL_MODEL_HEADER_BINARY "#celmodel_binary" - -class ModelLoader -{ - public: - ModelLoader(); - virtual ~ModelLoader(); - - virtual Model* load() = 0; - - const std::string& getErrorMessage() const; - void setTexturePath(const std::string&); - const std::string& getTexturePath() const; - - static ModelLoader* OpenModel(std::istream& in); - - protected: - virtual void reportError(const std::string&); - - private: - std::string errorMessage; - std::string texPath; -}; - - -class ModelWriter -{ - public: - virtual ~ModelWriter() {}; - - virtual bool write(const Model&) = 0; -}; - - - -Model* LoadModel(std::istream&); -Model* LoadModel(std::istream& in, const std::string& texPath); - -bool SaveModelAscii(const Model* model, std::ostream& out); -bool SaveModelBinary(const Model* model, std::ostream& out); - - -// Binary file tokens -enum ModelFileToken -{ - CMOD_Material = 1001, - CMOD_EndMaterial = 1002, - CMOD_Diffuse = 1003, - CMOD_Specular = 1004, - CMOD_SpecularPower = 1005, - CMOD_Opacity = 1006, - CMOD_Texture = 1007, - CMOD_Mesh = 1009, - CMOD_EndMesh = 1010, - CMOD_VertexDesc = 1011, - CMOD_EndVertexDesc = 1012, - CMOD_Vertices = 1013, - CMOD_Emissive = 1014, - CMOD_Blend = 1015, -}; - -enum ModelFileType -{ - CMOD_Float1 = 1, - CMOD_Float2 = 2, - CMOD_Float3 = 3, - CMOD_Float4 = 4, - CMOD_String = 5, - CMOD_Uint32 = 6, - CMOD_Color = 7, -}; - -#endif // !_CELMESH_MODELFILE_H_ Index: src/celengine/lodspheremesh.h =================================================================== --- src/celengine/lodspheremesh.h (revision 4952) +++ src/celengine/lodspheremesh.h (working copy) @@ -1,6 +1,7 @@ // lodspheremesh.h // -// Copyright (C) 2001, Chris Laurel +// Copyright (C) 2001-2010, Celestia Development Team +// Original version by Chris Laurel // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -10,11 +11,10 @@ #ifndef CELENGINE_LODSPHEREMESH_H_ #define CELENGINE_LODSPHEREMESH_H_ +#include +#include #include #include -#include -#include -#include #define MAX_SPHERE_MESH_TEXTURES 6 Index: src/celengine/render.cpp =================================================================== --- src/celengine/render.cpp (revision 4952) +++ src/celengine/render.cpp (working copy) @@ -51,7 +51,7 @@ #include "shadermanager.h" #include "spheremesh.h" #include "lodspheremesh.h" -#include "model.h" +#include "geometry.h" #include "regcombine.h" #include "vertexprog.h" #include "texmanager.h" @@ -62,6 +62,7 @@ #include "frametree.h" #include "timelinephase.h" #include "skygrid.h" +#include "modelgeometry.h" #include #include #include @@ -80,6 +81,7 @@ #include #include "eigenport.h" +using namespace cmod; using namespace Eigen; using namespace std; @@ -5015,7 +5017,7 @@ ResourceHandle texOverride) { FixedFunctionRenderContext rc; - Mesh::Material m; + Material m; rc.setLighting(lit); @@ -5033,16 +5035,19 @@ if (ri.baseTex != NULL) { - m.diffuse = ri.color; - m.specular = ri.specularColor; + m.diffuse = Material::Color(ri.color.red(), ri.color.green(), ri.color.blue()); + m.specular = Material::Color(ri.specularColor.red(), ri.specularColor.green(), ri.specularColor.blue()); m.specularPower = ri.specularPower; - m.maps[Mesh::DiffuseMap] = texOverride; + + CelestiaTextureResource textureResource(texOverride); + m.maps[Material::DiffuseMap] = &textureResource; + rc.setMaterial(&m); rc.lock(); } geometry->render(rc); - if (geometry->usesTextureType(Mesh::EmissiveMap)) + if (geometry->usesTextureType(Material::EmissiveMap)) { glDisable(GL_LIGHTING); glEnable(GL_BLEND); @@ -5055,6 +5060,7 @@ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } + m.maps[Material::DiffuseMap] = NULL; // prevent Material destructor from deleting the texture resource // Reset the material float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; Index: src/celengine/astro.h =================================================================== --- src/celengine/astro.h (revision 4952) +++ src/celengine/astro.h (working copy) @@ -137,29 +137,48 @@ return (T) (appMag + 5 - 5 * log10(lyrs / LY_PER_PARSEC)); } - // Distance conversions - float lightYearsToParsecs(float); - double lightYearsToParsecs(double); - float parsecsToLightYears(float); - double parsecsToLightYears(double); - float lightYearsToKilometers(float); - double lightYearsToKilometers(double); - float kilometersToLightYears(float); - double kilometersToLightYears(double); - float lightYearsToAU(float); - double lightYearsToAU(double); + /*** Distance conversions ***/ - // TODO: templatize the rest of the conversion functions + template T lightYearsToParsecs(T ly) + { + return ly / T(LY_PER_PARSEC); + } + + template T parsecsToLightYears(T pc) + { + return pc * T(LY_PER_PARSEC); + } + + template T lightYearsToKilometers(T ly) + { + return ly * T(KM_PER_LY); + } + + template T kilometersToLightYears(T km) + { + return km / T(KM_PER_LY); + } + + template T lightYearsToAU(T ly) + { + return ly * T(AU_PER_LY); + } + template T AUtoLightYears(T au) { - return au / (T) AU_PER_LY; + return au / T(AU_PER_LY); } - float AUtoKilometers(float); - double AUtoKilometers(double); - float kilometersToAU(float); - double kilometersToAU(double); + template T AUtoKilometers(T au) + { + return au * T(KM_PER_AU); + } + template T kilometersToAU(T km) + { + return km / T(KM_PER_AU); + } + float microLightYearsToKilometers(float); double microLightYearsToKilometers(double); float kilometersToMicroLightYears(float); Index: src/celengine/renderglsl.h =================================================================== --- src/celengine/renderglsl.h (revision 4952) +++ src/celengine/renderglsl.h (working copy) @@ -76,7 +76,53 @@ const Eigen::Quaternionf& planetOrientation, double tsec); - + +class FramebufferObject +{ +public: + enum + { + ColorAttachment = 0x1, + DepthAttachment = 0x2 + }; + FramebufferObject(GLuint width, GLuint height, unsigned int attachments); + ~FramebufferObject(); + + bool isValid() const; + GLuint width() const + { + return m_width; + } + + GLuint height() const + { + return m_height; + } + + GLuint colorTexture() const; + GLuint depthTexture() const; + + bool bind(); + bool unbind(); + + + +private: + void generateColorTexture(); + void generateDepthTexture(); + void generateFbo(unsigned int attachments); + void cleanup(); + +private: + GLuint m_width; + GLuint m_height; + GLuint m_colorTexId; + GLuint m_depthTexId; + GLuint m_fboId; + GLenum m_status; +}; + + #endif // _CELENGINE_RENDERGLSL_H_ Index: src/celengine/model.cpp =================================================================== --- src/celengine/model.cpp (revision 4952) +++ src/celengine/model.cpp (working copy) @@ -1,488 +0,0 @@ -// model.cpp -// -// Copyright (C) 2004-2006, Chris Laurel -// -// 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 "model.h" -#include "rendcontext.h" -#include "texmanager.h" -#include -#include -#include - -using namespace Eigen; -using namespace std; - - -#if 0 -static GLenum GLPrimitiveModes[MaxPrimitiveType] = -{ - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN, - GL_LINES, - GL_LINE_STRIP, - GL_POINTS -}; -#endif - -#if 0 -static size_t VertexAttributeFormatSizes[Mesh::FormatMax] = -{ - 4, // Float1 - 8, // Float2 - 12, // Float3 - 16, // Float4, - 4, // UByte4 -}; -#endif - - -Model::Model() : - opaque(true), - normalized(false) -{ - for (int i = 0; i < Mesh::TextureSemanticMax; i++) - textureUsage[i] = false; -} - - -Model::~Model() -{ - { - for (vector::iterator iter = meshes.begin(); - iter != meshes.end(); iter++) - delete *iter; - } - -#if 0 - { - for (vector::iterator iter = materials.begin(); - iter != materials.end(); iter++) - delete *iter; - } -#endif -} - - -const Mesh::Material* -Model::getMaterial(uint32 index) const -{ - if (index < materials.size()) - return materials[index]; - else - return NULL; -} - - -uint32 -Model::addMaterial(const Mesh::Material* m) -{ - // Update the texture map usage information for the model. Since - // the material being added isn't necessarily used by a mesh within - // the model, we could potentially end up with false positives--this - // won't cause any rendering troubles, but could hurt performance - // if it forces multipass rendering when it's not required. - for (int i = 0; i < Mesh::TextureSemanticMax; i++) - { - if (m->maps[i] != InvalidResource) - textureUsage[i] = true; - } - - materials.push_back(m); - return materials.size(); -} - - -uint32 -Model::getMaterialCount() const -{ - return materials.size(); -} - - -uint32 -Model::getVertexCount() const -{ - uint32 count = 0; - - for (vector::const_iterator iter = meshes.begin(); - iter != meshes.end(); iter++) - { - count += (*iter)->getVertexCount(); - } - - return count; -} - - -uint32 -Model::getPrimitiveCount() const -{ - uint32 count = 0; - - for (vector::const_iterator iter = meshes.begin(); - iter != meshes.end(); iter++) - { - count += (*iter)->getPrimitiveCount(); - } - - return count; -} - - -Mesh* -Model::getMesh(uint32 index) const -{ - if (index < meshes.size()) - return meshes[index]; - else - return NULL; -} - - -uint32 -Model::addMesh(Mesh* m) -{ - meshes.push_back(m); - return meshes.size(); -} - - -bool -Model::pick(const Ray3d& r, double& distance) const -{ - double maxDistance = 1.0e30; - double closest = maxDistance; - - for (vector::const_iterator iter = meshes.begin(); - iter != meshes.end(); iter++) - { - double d = maxDistance; - if ((*iter)->pick(r, d) && d < closest) - closest = d; - } - - if (closest != maxDistance) - { - distance = closest; - return true; - } - else - { - return false; - } -} - - -/*! Render the model; the time parameter is ignored right now - * since this class doesn't currently support animation. - */ -void -Model::render(RenderContext& rc, double /* t */) -{ - for (vector::const_iterator iter = meshes.begin(); - iter != meshes.end(); iter++) - { - (*iter)->render(materials, rc); - } -} - - -/*! Translate and scale a model. The transformation applied to - * each vertex in the model is: - * v' = (v + translation) * scale - */ -void -Model::transform(const Vector3f& translation, float scale) -{ - for (vector::const_iterator iter = meshes.begin(); iter != meshes.end(); iter++) - (*iter)->transform(translation, scale); -} - - -void -Model::normalize(const Vector3f& centerOffset) -{ - AlignedBox bbox; - - for (vector::const_iterator iter = meshes.begin(); iter != meshes.end(); iter++) - bbox.extend((*iter)->getBoundingBox()); - - Vector3f center = (bbox.min() + bbox.max()) * 0.5f + centerOffset; - Vector3f extents = bbox.max() - bbox.min(); - float maxExtent = extents.maxCoeff(); - - transform(-center, 2.0f / maxExtent); - - normalized = true; -} - - -static bool -operator<(const Color& c0, const Color& c1) -{ - if (c0.red() < c1.red()) - return true; - else if (c0.red() > c1.red()) - return false; - - if (c0.green() < c1.green()) - return true; - else if (c0.green() > c1.green()) - return false; - - return c0.blue() < c1.blue(); -} - - -// Define an ordering for materials; required for elimination of duplicate -// materials. -static bool -operator<(const Mesh::Material& m0, const Mesh::Material& m1) -{ - // Checking opacity first and doing it backwards is deliberate. It means - // that after sorting, translucent materials will end up with higher - // material indices than opaque ones. Ultimately, after sorting - // mesh primitive groups by material, translucent groups will end up - // rendered after opaque ones. - if (m0.opacity < m1.opacity) - return true; - else if (m0.opacity > m1.opacity) - return false; - - // Reverse sense of comparison here--additive blending is 1, normal - // blending is 0, and we'd prefer to render additively blended submeshes - // last. - if (m0.blend > m1.blend) - return true; - else if (m0.blend < m1.blend) - return false; - - if (m0.diffuse < m1.diffuse) - return true; - else if (m1.diffuse < m0.diffuse) - return false; - - if (m0.emissive < m1.emissive) - return true; - else if (m1.emissive < m0.emissive) - return false; - - if (m0.specular < m1.specular) - return true; - else if (m1.specular < m0.specular) - return false; - - if (m0.specularPower < m1.specularPower) - return true; - else if (m0.specularPower > m1.specularPower) - return false; - - for (unsigned int i = 0; i < Mesh::TextureSemanticMax; i++) - { - if (m0.maps[i] < m1.maps[i]) - return true; - else if (m0.maps[i] > m1.maps[i]) - return false; - } - - // Materials are identical - return false; -} - - -// Simple struct that pairs an index with a material; the index is used to -// keep track of the original material index after sorting. -struct IndexedMaterial -{ - int originalIndex; - const Mesh::Material* material; -}; - - -static bool -operator<(const IndexedMaterial& im0, const IndexedMaterial& im1) -{ - return *(im0.material) < *(im1.material); -} - - -static bool -operator!=(const IndexedMaterial& im0, const IndexedMaterial& im1) -{ - return im0 < im1 || im1 < im0; -} - - -void -Model::uniquifyMaterials() -{ - // No work to do if there's just a single material - if (materials.size() <= 1) - return; - - // Create an array of materials with the indices attached - vector indexedMaterials; - unsigned int i; - for (i = 0; i < materials.size(); i++) - { - IndexedMaterial im; - im.originalIndex = i; - im.material = materials[i]; - indexedMaterials.push_back(im); - } - - // Sort the indexed materials so that we can uniquify them - sort(indexedMaterials.begin(), indexedMaterials.end()); - - vector uniqueMaterials; - vector materialMap(materials.size()); - vector duplicateMaterials; - - // From the sorted material list construct the list of unique materials - // and a map to convert old material indices into indices that can be - // used with the uniquified material list. - unsigned int uniqueMaterialCount = 0; - for (i = 0; i < indexedMaterials.size(); i++) - { - if (i == 0 || indexedMaterials[i] != indexedMaterials[i - 1]) - { - uniqueMaterialCount++; - uniqueMaterials.push_back(indexedMaterials[i].material); - } - else - { - duplicateMaterials.push_back(i); - } - materialMap[indexedMaterials[i].originalIndex] = uniqueMaterialCount - 1; - } - - // Remap all the material indices in the model. Even if no materials have - // been eliminated we've still sorted them by opacity, which is useful - // when reordering meshes so that translucent ones are rendered last. - for (vector::iterator iter = meshes.begin(); - iter != meshes.end(); iter++) - { - (*iter)->remapMaterials(materialMap); - } - - vector::const_iterator dupIter; - for (dupIter = duplicateMaterials.begin(); - dupIter != duplicateMaterials.end(); ++dupIter) - { - delete indexedMaterials[*dupIter].material; - } - - materials = uniqueMaterials; -} - - -void -Model::determineOpacity() -{ - for (unsigned int i = 0; i < materials.size(); i++) - { - if ((materials[i]->opacity > 0.01f && materials[i]->opacity < 1.0f) || - materials[i]->blend == Mesh::AdditiveBlend) - { - opaque = false; - return; - } - } - - opaque = true; -} - - -bool -Model::usesTextureType(Mesh::TextureSemantic t) const -{ - return textureUsage[static_cast(t)]; -} - - -class MeshComparatorAdapter : public std::binary_function -{ -public: - MeshComparatorAdapter(const Model::MeshComparator& c) : - comparator(c) - { - } - - bool operator()(const Mesh* a, const Mesh* b) const - { - return comparator(*a, *b); - } - -private: - const Model::MeshComparator& comparator; -}; - - -Model::OpacityComparator::OpacityComparator() -{ -} - - -// Look at the material used by last primitive group in the mesh for the -// opacity of the whole model. This is a very crude way to check the opacity -// of a mesh and misses many cases. -static uint32 -getMeshMaterialIndex(const Mesh& mesh) -{ - if (mesh.getGroupCount() == 0) - return 0; - else - return mesh.getGroup(mesh.getGroupCount() - 1)->materialIndex; -} - - - -bool -Model::OpacityComparator::operator()(const Mesh& a, const Mesh& b) const -{ - // Because materials are sorted by opacity, we can just compare - // the material index. - return getMeshMaterialIndex(a) > getMeshMaterialIndex(b); -} - - -void -Model::sortMeshes(const MeshComparator& comparator) -{ - // Sort submeshes by material; if materials have been uniquified, - // then the submeshes will be ordered so that opaque ones are first. - for (vector::const_iterator iter = meshes.begin(); - iter != meshes.end(); iter++) - { - (*iter)->aggregateByMaterial(); - } - - // Sort the meshes so that completely opaque ones are first - sort(meshes.begin(), meshes.end(), MeshComparatorAdapter(comparator)); -} - - -void -Model::loadTextures() -{ - for (vector::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]); - } -} Index: src/celengine/mesh.h =================================================================== --- src/celengine/mesh.h (revision 4952) +++ src/celengine/mesh.h (working copy) @@ -1,231 +0,0 @@ -// mesh.h -// -// Copyright (C) 2004-2006, Chris Laurel -// -// 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. - -#ifndef _CELENGINE_MESH_H_ -#define _CELENGINE_MESH_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -class RenderContext; - -class Mesh -{ - public: - enum VertexAttributeSemantic - { - Position = 0, - Color0 = 1, - Color1 = 2, - Normal = 3, - Tangent = 4, - Texture0 = 5, - Texture1 = 6, - Texture2 = 7, - Texture3 = 8, - PointSize = 9, - SemanticMax = 10, - InvalidSemantic = -1, - }; - - enum VertexAttributeFormat - { - Float1 = 0, - Float2 = 1, - Float3 = 2, - Float4 = 3, - UByte4 = 4, - FormatMax = 5, - InvalidFormat = -1, - }; - - struct VertexAttribute - { - VertexAttribute() : - semantic(InvalidSemantic), - format(InvalidFormat), - offset(0) - { - } - - VertexAttribute(VertexAttributeSemantic _semantic, - VertexAttributeFormat _format, - uint32 _offset) : - semantic(_semantic), - format(_format), - offset(_offset) - { - } - - VertexAttributeSemantic semantic; - VertexAttributeFormat format; - uint32 offset; - }; - - struct VertexDescription - { - VertexDescription(uint32 _stride, - uint32 _nAttributes, - VertexAttribute* _attributes); - VertexDescription(const VertexDescription& desc); - ~VertexDescription(); - - const VertexAttribute& getAttribute(VertexAttributeSemantic semantic) const - { - return semanticMap[semantic]; - } - - bool validate() const; - - VertexDescription& operator=(const VertexDescription&); - - uint32 stride; - uint32 nAttributes; - VertexAttribute* attributes; - - private: - void clearSemanticMap(); - void buildSemanticMap(); - - // Vertex attributes indexed by semantic - VertexAttribute semanticMap[SemanticMax]; - }; - - enum TextureSemantic - { - DiffuseMap = 0, - NormalMap = 1, - SpecularMap = 2, - EmissiveMap = 3, - TextureSemanticMax = 4, - InvalidTextureSemantic = -1, - }; - - enum BlendMode - { - NormalBlend = 0, - AdditiveBlend = 1, - PremultipliedAlphaBlend = 2, - BlendMax = 3, - InvalidBlend = -1, - }; - - class Material - { - public: - Material(); - - Color diffuse; - Color emissive; - Color specular; - float specularPower; - float opacity; - BlendMode blend; - ResourceHandle maps[TextureSemanticMax]; - }; - - enum PrimitiveGroupType - { - TriList = 0, - TriStrip = 1, - TriFan = 2, - LineList = 3, - LineStrip = 4, - PointList = 5, - SpriteList = 6, - PrimitiveTypeMax = 7, - InvalidPrimitiveGroupType = -1 - }; - - class PrimitiveGroup - { - public: - PrimitiveGroup(); - ~PrimitiveGroup(); - - uint32 getPrimitiveCount() const; - - PrimitiveGroupType prim; - uint32 materialIndex; - uint32* indices; - uint32 nIndices; - }; - - Mesh(); - ~Mesh(); - - void setVertices(uint32 _nVertices, void* vertexData); - bool setVertexDescription(const VertexDescription& desc); - const VertexDescription& getVertexDescription() const; - - const PrimitiveGroup* getGroup(uint32) const; - uint32 addGroup(PrimitiveGroup* group); - uint32 addGroup(PrimitiveGroupType prim, - uint32 materialIndex, - uint32 nIndices, - uint32* indices); - uint32 getGroupCount() const; - void remapIndices(const std::vector& indexMap); - void clearGroups(); - - void remapMaterials(const std::vector& materialMap); - - /*! Reorder primitive groups so that groups with identical materials - * appear sequentially in the primitive group list. This will reduce - * the number of graphics state changes at render time. - */ - void aggregateByMaterial(); - - const std::string& getName() const; - void setName(const std::string&); - - bool pick(const Ray3d& r, double& distance) const; - void render(const std::vector& materials, - RenderContext&) const; - - Eigen::AlignedBox getBoundingBox() const; - void transform(const Eigen::Vector3f& translation, float scale); - - const void* getVertexData() const { return vertices; } - uint32 getVertexCount() const { return nVertices; } - uint32 getVertexStride() const { return vertexDesc.stride; } - uint32 getPrimitiveCount() const; - - static PrimitiveGroupType parsePrimitiveGroupType(const std::string&); - static VertexAttributeSemantic parseVertexAttributeSemantic(const std::string&); - static VertexAttributeFormat parseVertexAttributeFormat(const std::string&); - static TextureSemantic parseTextureSemantic(const std::string&); - static uint32 getVertexAttributeSize(VertexAttributeFormat); - - private: - void recomputeBoundingBox(); - - private: - VertexDescription vertexDesc; - - uint32 nVertices; - void* vertices; - mutable GLuint vbObject; - mutable bool vbInitialized; - - std::vector groups; - - std::string name; -}; - -#endif // !_CELMESH_MESH_H_ - Index: src/celengine/meshmanager.h =================================================================== --- src/celengine/meshmanager.h (revision 4952) +++ src/celengine/meshmanager.h (working copy) @@ -13,7 +13,7 @@ #include #include #include -#include +#include class GeometryInfo : public ResourceInfo Index: src/celengine/modelfile.cpp =================================================================== --- src/celengine/modelfile.cpp (revision 4952) +++ src/celengine/modelfile.cpp (working copy) @@ -1,1903 +0,0 @@ -// modelfile.cpp -// -// Copyright (C) 2004, Chris Laurel -// -// 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 "modelfile.h" -#include "tokenizer.h" -#include "texmanager.h" -#include -#include -#include -#include -#include - -using namespace std; - - - -// Material default values -static Color DefaultDiffuse(0.0f, 0.0f, 0.0f); -static Color DefaultSpecular(0.0f, 0.0f, 0.0f); -static Color DefaultEmissive(0.0f, 0.0f, 0.0f); -static float DefaultSpecularPower = 1.0f; -static float DefaultOpacity = 1.0f; -static Mesh::BlendMode DefaultBlend = Mesh::NormalBlend; - - -/*! -This is an approximate Backus Naur form for the contents of ASCII cmod -files. For brevity, the categories <unsigned_int> and <float> aren't -defined here--they have the obvious definitions. -\code - ::=
- -
::= #celmodel__ascii - - ::= { } { } - - ::= material - { } - end_material - - ::= texture0 | - normalmap | - specularmap | - emissivemap - - ::= - - ::= diffuse | - specular | - emissive | - specpower | - opacity | - blend | - - - ::= - - ::= """ { letter } """ - - ::= normal | add | premultiplied - - ::= mesh - - - { } - end_mesh - - ::= vertexdesc - { } - end_vertexdesc - - ::= - - ::= position | normal | color0 | color1 | tangent | - texcoord0 | texcoord1 | texcoord2 | texcoord3 | - pointsize - - ::= f1 | f2 | f3 | f4 | ub4 - - ::= vertices - { } - - ::= - - ::= - { } - - ::= trilist | tristrip | trifan | - linelist | linestrip | points | - sprites - - :: | -1 -\endcode -*/ -class AsciiModelLoader : public ModelLoader -{ -public: - AsciiModelLoader(istream& _in); - ~AsciiModelLoader(); - - virtual Model* load(); - virtual void reportError(const string&); - - Mesh::Material* loadMaterial(); - Mesh::VertexDescription* loadVertexDescription(); - Mesh* loadMesh(); - char* loadVertices(const Mesh::VertexDescription& vertexDesc, - uint32& vertexCount); - -private: - Tokenizer tok; -}; - - -class AsciiModelWriter : public ModelWriter -{ -public: - AsciiModelWriter(ostream&); - ~AsciiModelWriter(); - - virtual bool write(const Model&); - -private: - void writeMesh(const Mesh&); - void writeMaterial(const Mesh::Material&); - void writeGroup(const Mesh::PrimitiveGroup&); - void writeVertexDescription(const Mesh::VertexDescription&); - void writeVertices(const void* vertexData, - uint32 nVertices, - uint32 stride, - const Mesh::VertexDescription& desc); - - ostream& out; -}; - - -class BinaryModelLoader : public ModelLoader -{ -public: - BinaryModelLoader(istream& _in); - ~BinaryModelLoader(); - - virtual Model* load(); - virtual void reportError(const string&); - - Mesh::Material* loadMaterial(); - Mesh::VertexDescription* loadVertexDescription(); - Mesh* loadMesh(); - char* loadVertices(const Mesh::VertexDescription& vertexDesc, - uint32& vertexCount); - -private: - istream& in; -}; - - -class BinaryModelWriter : public ModelWriter -{ -public: - BinaryModelWriter(ostream&); - ~BinaryModelWriter(); - - virtual bool write(const Model&); - -private: - void writeMesh(const Mesh&); - void writeMaterial(const Mesh::Material&); - void writeGroup(const Mesh::PrimitiveGroup&); - void writeVertexDescription(const Mesh::VertexDescription&); - void writeVertices(const void* vertexData, - uint32 nVertices, - uint32 stride, - const Mesh::VertexDescription& desc); - - ostream& out; -}; - - -ModelLoader::ModelLoader() -{ -} - - -ModelLoader::~ModelLoader() -{ -} - - -void -ModelLoader::reportError(const string& msg) -{ - errorMessage = msg; -} - - -const string& -ModelLoader::getErrorMessage() const -{ - return errorMessage; -} - - -void -ModelLoader::setTexturePath(const string& _texPath) -{ - texPath = _texPath; -} - - -const string& -ModelLoader::getTexturePath() const -{ - return texPath; -} - - -Model* LoadModel(istream& in) -{ - return LoadModel(in, ""); -} - - -Model* LoadModel(istream& in, const string& texPath) -{ - ModelLoader* loader = ModelLoader::OpenModel(in); - if (loader == NULL) - return NULL; - - loader->setTexturePath(texPath); - - Model* model = loader->load(); - if (model == NULL) - cerr << "Error in model file: " << loader->getErrorMessage() << '\n'; - - delete loader; - - return model; -} - - -ModelLoader* -ModelLoader::OpenModel(istream& in) -{ - char header[CEL_MODEL_HEADER_LENGTH + 1]; - memset(header, '\0', sizeof(header)); - - in.read(header, CEL_MODEL_HEADER_LENGTH); - if (strcmp(header, CEL_MODEL_HEADER_ASCII) == 0) - { - return new AsciiModelLoader(in); - } - else if (strcmp(header, CEL_MODEL_HEADER_BINARY) == 0) - { - return new BinaryModelLoader(in); - } - else - { - cerr << "Model file has invalid header.\n"; - return NULL; - } -} - - -bool SaveModelAscii(const Model* model, std::ostream& out) -{ - if (model == NULL) - return false; - - AsciiModelWriter(out).write(*model); - - return true; -} - - -bool SaveModelBinary(const Model* model, std::ostream& out) -{ - if (model == NULL) - return false; - - BinaryModelWriter(out).write(*model); - - return true; -} - - -AsciiModelLoader::AsciiModelLoader(istream& _in) : - tok(&_in) -{ -} - - -AsciiModelLoader::~AsciiModelLoader() -{ -} - - -void -AsciiModelLoader::reportError(const string& msg) -{ - char buf[32]; - sprintf(buf, " (line %d)", tok.getLineNumber()); - ModelLoader::reportError(msg + string(buf)); -} - - -Mesh::Material* -AsciiModelLoader::loadMaterial() -{ - if (tok.nextToken() != Tokenizer::TokenName || - tok.getNameValue() != "material") - { - reportError("Material definition expected"); - return NULL; - } - - Mesh::Material* material = new Mesh::Material(); - - material->diffuse = DefaultDiffuse; - material->specular = DefaultSpecular; - material->emissive = DefaultEmissive; - material->specularPower = DefaultSpecularPower; - material->opacity = DefaultOpacity; - - while (tok.nextToken() == Tokenizer::TokenName && - tok.getNameValue() != "end_material") - { - string property = tok.getNameValue(); - Mesh::TextureSemantic texType = Mesh::parseTextureSemantic(property); - - if (texType != Mesh::InvalidTextureSemantic) - { - if (tok.nextToken() != Tokenizer::TokenString) - { - reportError("Texture name expected"); - delete material; - return NULL; - } - - ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(tok.getStringValue(), getTexturePath(), TextureInfo::WrapTexture)); - - material->maps[texType] = tex; - } - else if (property == "blend") - { - Mesh::BlendMode blendMode = Mesh::InvalidBlend; - - if (tok.nextToken() == Tokenizer::TokenName) - { - string blendModeName = tok.getNameValue(); - if (blendModeName == "normal") - blendMode = Mesh::NormalBlend; - else if (blendModeName == "add") - blendMode = Mesh::AdditiveBlend; - else if (blendModeName == "premultiplied") - blendMode = Mesh::PremultipliedAlphaBlend; - } - - if (blendMode == Mesh::InvalidBlend) - { - reportError("Bad blend mode in material"); - delete material; - return NULL; - } - - material->blend = blendMode; - } - else - { - // All non-texture material properties are 3-vectors except - // specular power and opacity - double data[3]; - int nValues = 3; - if (property == "specpower" || property == "opacity") - nValues = 1; - - for (int i = 0; i < nValues; i++) - { - if (tok.nextToken() != Tokenizer::TokenNumber) - { - reportError("Bad property value in material"); - delete material; - return NULL; - } - data[i] = tok.getNumberValue(); - } - - Color colorVal; - if (nValues == 3) - colorVal = Color((float) data[0], (float) data[1], (float) data[2]); - - if (property == "diffuse") - material->diffuse = colorVal; - else if (property == "specular") - material->specular = colorVal; - else if (property == "emissive") - material->emissive = colorVal; - else if (property == "opacity") - material->opacity = (float) data[0]; - else if (property == "specpower") - material->specularPower = (float) data[0]; - } - } - - if (tok.getTokenType() != Tokenizer::TokenName) - { - delete material; - return NULL; - } - else - { - return material; - } -} - - -Mesh::VertexDescription* -AsciiModelLoader::loadVertexDescription() -{ - if (tok.nextToken() != Tokenizer::TokenName || - tok.getNameValue() != "vertexdesc") - { - reportError("Vertex description expected"); - return NULL; - } - - int maxAttributes = 16; - int nAttributes = 0; - uint32 offset = 0; - Mesh::VertexAttribute* attributes = new Mesh::VertexAttribute[maxAttributes]; - - while (tok.nextToken() == Tokenizer::TokenName && - tok.getNameValue() != "end_vertexdesc") - { - string semanticName; - string formatName; - bool valid = false; - - if (nAttributes == maxAttributes) - { - // TODO: Should eliminate the attribute limit, though no real vertex - // will ever exceed it. - reportError("Attribute limit exceeded in vertex description"); - delete[] attributes; - return NULL; - } - - semanticName = tok.getNameValue(); - - if (tok.nextToken() == Tokenizer::TokenName) - { - formatName = tok.getNameValue(); - valid = true; - } - - if (!valid) - { - reportError("Invalid vertex description"); - delete[] attributes; - return NULL; - } - - Mesh::VertexAttributeSemantic semantic = - Mesh::parseVertexAttributeSemantic(semanticName); - if (semantic == Mesh::InvalidSemantic) - { - reportError(string("Invalid vertex attribute semantic '") + - semanticName + "'"); - delete[] attributes; - return NULL; - } - - Mesh::VertexAttributeFormat format = - Mesh::parseVertexAttributeFormat(formatName); - if (format == Mesh::InvalidFormat) - { - reportError(string("Invalid vertex attribute format '") + - formatName + "'"); - delete[] attributes; - return NULL; - } - - attributes[nAttributes].semantic = semantic; - attributes[nAttributes].format = format; - attributes[nAttributes].offset = offset; - - offset += Mesh::getVertexAttributeSize(format); - nAttributes++; - } - - if (tok.getTokenType() != Tokenizer::TokenName) - { - reportError("Invalid vertex description"); - delete[] attributes; - return NULL; - } - - if (nAttributes == 0) - { - reportError("Vertex definitition cannot be empty"); - delete[] attributes; - return NULL; - } - - Mesh::VertexDescription *vertexDesc = - new Mesh::VertexDescription(offset, nAttributes, attributes); - delete[] attributes; - return vertexDesc; -} - - -char* -AsciiModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc, - uint32& vertexCount) -{ - if (tok.nextToken() != Tokenizer::TokenName || - tok.getNameValue() != "vertices") - { - reportError("Vertex data expected"); - return NULL; - } - - if (tok.nextToken() != Tokenizer::TokenNumber) - { - reportError("Vertex count expected"); - return NULL; - } - - double num = tok.getNumberValue(); - if (num != floor(num) || num <= 0.0) - { - reportError("Bad vertex count for mesh"); - return NULL; - } - - vertexCount = (uint32) num; - uint32 vertexDataSize = vertexDesc.stride * vertexCount; - char* vertexData = new char[vertexDataSize]; - if (vertexData == NULL) - { - reportError("Not enough memory to hold vertex data"); - return NULL; - } - - uint32 offset = 0; - double data[4]; - for (uint32 i = 0; i < vertexCount; i++, offset += vertexDesc.stride) - { - assert(offset < vertexDataSize); - for (uint32 attr = 0; attr < vertexDesc.nAttributes; attr++) - { - Mesh::VertexAttributeFormat fmt = vertexDesc.attributes[attr].format; - /*uint32 nBytes = Mesh::getVertexAttributeSize(fmt); Unused*/ - int readCount = 0; - switch (fmt) - { - case Mesh::Float1: - readCount = 1; - break; - case Mesh::Float2: - readCount = 2; - break; - case Mesh::Float3: - readCount = 3; - break; - case Mesh::Float4: - case Mesh::UByte4: - readCount = 4; - break; - default: - assert(0); - delete[] vertexData; - return NULL; - } - - for (int j = 0; j < readCount; j++) - { - if (tok.nextToken() != Tokenizer::TokenNumber) - { - reportError("Error in vertex data"); - data[j] = 0.0; - } - else - { - data[j] = tok.getNumberValue(); - } - // TODO: range check unsigned byte values - } - - uint32 base = offset + vertexDesc.attributes[attr].offset; - if (fmt == Mesh::UByte4) - { - for (int k = 0; k < readCount; k++) - { - reinterpret_cast(vertexData + base)[k] = - (unsigned char) (data[k]); - } - } - else - { - for (int k = 0; k < readCount; k++) - reinterpret_cast(vertexData + base)[k] = (float) data[k]; - } - } - } - - return vertexData; -} - - -Mesh* -AsciiModelLoader::loadMesh() -{ - if (tok.nextToken() != Tokenizer::TokenName || - tok.getNameValue() != "mesh") - { - reportError("Mesh definition expected"); - return NULL; - } - - Mesh::VertexDescription* vertexDesc = loadVertexDescription(); - if (vertexDesc == NULL) - return NULL; - - uint32 vertexCount = 0; - char* vertexData = loadVertices(*vertexDesc, vertexCount); - if (vertexData == NULL) - { - delete vertexDesc; - return NULL; - } - - Mesh* mesh = new Mesh(); - mesh->setVertexDescription(*vertexDesc); - mesh->setVertices(vertexCount, vertexData); - delete vertexDesc; - - while (tok.nextToken() == Tokenizer::TokenName && - tok.getNameValue() != "end_mesh") - { - Mesh::PrimitiveGroupType type = - Mesh::parsePrimitiveGroupType(tok.getNameValue()); - if (type == Mesh::InvalidPrimitiveGroupType) - { - reportError("Bad primitive group type: " + tok.getNameValue()); - delete mesh; - return NULL; - } - - if (tok.nextToken() != Tokenizer::TokenNumber) - { - reportError("Material index expected in primitive group"); - delete mesh; - return NULL; - } - - uint32 materialIndex; - if (tok.getNumberValue() == -1.0) - materialIndex = ~0u; - else - materialIndex = (uint32) tok.getNumberValue(); - - if (tok.nextToken() != Tokenizer::TokenNumber) - { - reportError("Index count expected in primitive group"); - delete mesh; - return NULL; - } - - uint32 indexCount = (uint32) tok.getNumberValue(); - - uint32* indices = new uint32[indexCount]; - if (indices == NULL) - { - reportError("Not enough memory to hold indices"); - delete mesh; - return NULL; - } - - for (uint32 i = 0; i < indexCount; i++) - { - if (tok.nextToken() != Tokenizer::TokenNumber) - { - reportError("Incomplete index list in primitive group"); - delete indices; - delete mesh; - return NULL; - } - - uint32 index = (uint32) tok.getNumberValue(); - if (index >= vertexCount) - { - reportError("Index out of range"); - delete indices; - delete mesh; - return NULL; - } - - indices[i] = index; - } - - mesh->addGroup(type, materialIndex, indexCount, indices); - } - - return mesh; -} - - -Model* -AsciiModelLoader::load() -{ - Model* model = new Model(); - bool seenMeshes = false; - - if (model == NULL) - { - reportError("Unable to allocate memory for model"); - return NULL; - } - - // Parse material and mesh definitions - for (;;) - { - Tokenizer::TokenType ttype = tok.nextToken(); - - if (ttype == Tokenizer::TokenEnd) - { - break; - } - else if (ttype == Tokenizer::TokenName) - { - string name = tok.getNameValue(); - tok.pushBack(); - - if (name == "material") - { - if (seenMeshes) - { - reportError("Materials must be defined before meshes"); - delete model; - return NULL; - } - - Mesh::Material* material = loadMaterial(); - if (material == NULL) - { - delete model; - return NULL; - } - - model->addMaterial(material); - } - else if (name == "mesh") - { - seenMeshes = true; - - Mesh* mesh = loadMesh(); - if (mesh == NULL) - { - delete model; - return NULL; - } - - model->addMesh(mesh); - } - else - { - reportError(string("Error: Unknown block type ") + name); - delete model; - return NULL; - } - } - else - { - reportError("Block name expected"); - return NULL; - } - } - - return model; -} - - - -AsciiModelWriter::AsciiModelWriter(ostream& _out) : - out(_out) -{ -} - - -AsciiModelWriter::~AsciiModelWriter() -{ -} - - -bool -AsciiModelWriter::write(const Model& model) -{ - out << CEL_MODEL_HEADER_ASCII << "\n\n"; - - for (uint32 matIndex = 0; model.getMaterial(matIndex); matIndex++) - { - writeMaterial(*model.getMaterial(matIndex)); - out << '\n'; - } - - for (uint32 meshIndex = 0; model.getMesh(meshIndex); meshIndex++) - { - writeMesh(*model.getMesh(meshIndex)); - out << '\n'; - } - - return true; -} - - -void -AsciiModelWriter::writeGroup(const Mesh::PrimitiveGroup& group) -{ - switch (group.prim) - { - case Mesh::TriList: - out << "trilist"; break; - case Mesh::TriStrip: - out << "tristrip"; break; - case Mesh::TriFan: - out << "trifan"; break; - case Mesh::LineList: - out << "linelist"; break; - case Mesh::LineStrip: - out << "linestrip"; break; - case Mesh::PointList: - out << "points"; break; - case Mesh::SpriteList: - out << "sprites"; break; - default: - return; - } - - out << ' ' << group.materialIndex << ' ' << group.nIndices << '\n'; - - // Print the indices, twelve per line - for (uint32 i = 0; i < group.nIndices; i++) - { - out << group.indices[i]; - if (i % 12 == 11 || i == group.nIndices - 1) - out << '\n'; - else - out << ' '; - } -} - - -void -AsciiModelWriter::writeMesh(const Mesh& mesh) -{ - out << "mesh\n"; - - if (!mesh.getName().empty()) - out << "# " << mesh.getName() << '\n'; - - writeVertexDescription(mesh.getVertexDescription()); - out << '\n'; - - writeVertices(mesh.getVertexData(), - mesh.getVertexCount(), - mesh.getVertexStride(), - mesh.getVertexDescription()); - out << '\n'; - - for (uint32 groupIndex = 0; mesh.getGroup(groupIndex); groupIndex++) - { - writeGroup(*mesh.getGroup(groupIndex)); - out << '\n'; - } - - out << "end_mesh\n"; -} - - -void -AsciiModelWriter::writeVertices(const void* vertexData, - uint32 nVertices, - uint32 stride, - const Mesh::VertexDescription& desc) -{ - const unsigned char* vertex = reinterpret_cast(vertexData); - - out << "vertices " << nVertices << '\n'; - for (uint32 i = 0; i < nVertices; i++, vertex += stride) - { - for (uint32 attr = 0; attr < desc.nAttributes; attr++) - { - const unsigned char* ubdata = vertex + desc.attributes[attr].offset; - const float* fdata = reinterpret_cast(ubdata); - - switch (desc.attributes[attr].format) - { - case Mesh::Float1: - out << fdata[0]; - break; - case Mesh::Float2: - out << fdata[0] << ' ' << fdata[1]; - break; - case Mesh::Float3: - out << fdata[0] << ' ' << fdata[1] << ' ' << fdata[2]; - break; - case Mesh::Float4: - out << fdata[0] << ' ' << fdata[1] << ' ' << - fdata[2] << ' ' << fdata[3]; - break; - case Mesh::UByte4: - out << (int) ubdata[0] << ' ' << (int) ubdata[1] << ' ' << - (int) ubdata[2] << ' ' << (int) ubdata[3]; - break; - default: - assert(0); - break; - } - - out << ' '; - } - - out << '\n'; - } -} - - -void -AsciiModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc) -{ - out << "vertexdesc\n"; - for (uint32 attr = 0; attr < desc.nAttributes; attr++) - { - // We should never have a vertex description with invalid - // fields . . . - - switch (desc.attributes[attr].semantic) - { - case Mesh::Position: - out << "position"; - break; - case Mesh::Color0: - out << "color0"; - break; - case Mesh::Color1: - out << "color1"; - break; - case Mesh::Normal: - out << "normal"; - break; - case Mesh::Tangent: - out << "tangent"; - break; - case Mesh::Texture0: - out << "texcoord0"; - break; - case Mesh::Texture1: - out << "texcoord1"; - break; - case Mesh::Texture2: - out << "texcoord2"; - break; - case Mesh::Texture3: - out << "texcoord3"; - break; - case Mesh::PointSize: - out << "pointsize"; - break; - default: - assert(0); - break; - } - - out << ' '; - - switch (desc.attributes[attr].format) - { - case Mesh::Float1: - out << "f1"; - break; - case Mesh::Float2: - out << "f2"; - break; - case Mesh::Float3: - out << "f3"; - break; - case Mesh::Float4: - out << "f4"; - break; - case Mesh::UByte4: - out << "ub4"; - break; - default: - assert(0); - break; - } - - out << '\n'; - } - out << "end_vertexdesc\n"; -} - - -void -AsciiModelWriter::writeMaterial(const Mesh::Material& material) -{ - out << "material\n"; - if (material.diffuse != DefaultDiffuse) - { - out << "diffuse " << - material.diffuse.red() << ' ' << - material.diffuse.green() << ' ' << - material.diffuse.blue() << '\n'; - } - - if (material.emissive != DefaultEmissive) - { - out << "emissive " << - material.emissive.red() << ' ' << - material.emissive.green() << ' ' << - material.emissive.blue() << '\n'; - } - - if (material.specular != DefaultSpecular) - { - out << "specular " << - material.specular.red() << ' ' << - material.specular.green() << ' ' << - material.specular.blue() << '\n'; - } - - if (material.specularPower != DefaultSpecularPower) - out << "specpower " << material.specularPower << '\n'; - - if (material.opacity != DefaultOpacity) - out << "opacity " << material.opacity << '\n'; - - if (material.blend != DefaultBlend) - { - out << "blend "; - switch (material.blend) - { - case Mesh::NormalBlend: - out << "normal"; - break; - case Mesh::AdditiveBlend: - out << "add"; - break; - case Mesh::PremultipliedAlphaBlend: - out << "premultiplied"; - break; - default: - assert(0); - break; - } - out << "\n"; - } - - for (int i = 0; i < Mesh::TextureSemanticMax; i++) - { - const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.maps[i]); - if (texInfo != NULL) - { - switch (Mesh::TextureSemantic(i)) - { - case Mesh::DiffuseMap: - out << "texture0"; - break; - case Mesh::NormalMap: - out << "normalmap"; - break; - case Mesh::SpecularMap: - out << "specularmap"; - break; - case Mesh::EmissiveMap: - out << "emissivemap"; - break; - default: - assert(0); - } - - out << " \"" << texInfo->source << "\"\n"; - } - } - -#if 0 - if (material.maps[Mesh::DiffuseMap] != InvalidResource) - { - const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.tex0); - if (texInfo != NULL) - out << "texture0 \"" << texInfo->source << "\"\n"; - } - - if (material.tex1 != InvalidResource) - { - const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.tex1); - if (texInfo != NULL) - out << "texture1 \"" << texInfo->source << "\"\n"; - } -#endif - - - out << "end_material\n"; -} - - -/***** Binary loader *****/ - -BinaryModelLoader::BinaryModelLoader(istream& _in) : - in(_in) -{ -} - - -BinaryModelLoader::~BinaryModelLoader() -{ -} - - -void -BinaryModelLoader::reportError(const string& msg) -{ - char buf[32]; - sprintf(buf, " (offset %d)", 0); - ModelLoader::reportError(msg + string(buf)); -} - - -// Read a big-endian 32-bit unsigned integer -static int32 readUint(istream& in) -{ - int32 ret; - in.read((char*) &ret, sizeof(int32)); - LE_TO_CPU_INT32(ret, ret); - return (uint32) ret; -} - - -static float readFloat(istream& in) -{ - float f; - in.read((char*) &f, sizeof(float)); - LE_TO_CPU_FLOAT(f, f); - return f; -} - - -static int16 readInt16(istream& in) -{ - int16 ret; - in.read((char *) &ret, sizeof(int16)); - LE_TO_CPU_INT16(ret, ret); - return ret; -} - - -static ModelFileToken readToken(istream& in) -{ - return (ModelFileToken) readInt16(in); -} - - -static ModelFileType readType(istream& in) -{ - return (ModelFileType) readInt16(in); -} - - -static bool readTypeFloat1(istream& in, float& f) -{ - if (readType(in) != CMOD_Float1) - return false; - f = readFloat(in); - return true; -} - - -static bool readTypeColor(istream& in, Color& c) -{ - if (readType(in) != CMOD_Color) - return false; - - float r = readFloat(in); - float g = readFloat(in); - float b = readFloat(in); - c = Color(r, g, b); - - return true; -} - - -static bool readTypeString(istream& in, string& s) -{ - if (readType(in) != CMOD_String) - return false; - - uint16 len; - in.read((char*) &len, sizeof(uint16)); - LE_TO_CPU_INT16(len, len); - - if (len == 0) - { - s = ""; - } - else - { - char* buf = new char[len]; - in.read(buf, len); - s = string(buf, len); - delete[] buf; - } - - return true; -} - - -static bool ignoreValue(istream& in) -{ - ModelFileType type = readType(in); - int size = 0; - - switch (type) - { - case CMOD_Float1: - size = 4; - break; - case CMOD_Float2: - size = 8; - break; - case CMOD_Float3: - size = 12; - break; - case CMOD_Float4: - size = 16; - break; - case CMOD_Uint32: - size = 4; - break; - case CMOD_Color: - size = 12; - break; - case CMOD_String: - { - uint16 len; - in.read((char*) &len, sizeof(uint16)); - LE_TO_CPU_INT16(len, len); - size = len; - } - break; - - default: - return false; - } - - in.ignore(size); - - return true; -} - - -Model* -BinaryModelLoader::load() -{ - Model* model = new Model(); - bool seenMeshes = false; - - if (model == NULL) - { - reportError("Unable to allocate memory for model"); - return NULL; - } - - // Parse material and mesh definitions - for (;;) - { - ModelFileToken tok = readToken(in); - - if (in.eof()) - { - break; - } - else if (tok == CMOD_Material) - { - if (seenMeshes) - { - reportError("Materials must be defined before meshes"); - delete model; - return NULL; - } - - Mesh::Material* material = loadMaterial(); - if (material == NULL) - { - delete model; - return NULL; - } - - model->addMaterial(material); - } - else if (tok == CMOD_Mesh) - { - seenMeshes = true; - - Mesh* mesh = loadMesh(); - if (mesh == NULL) - { - delete model; - return NULL; - } - - model->addMesh(mesh); - } - else - { - reportError("Error: Unknown block type in model"); - delete model; - return NULL; - } - } - - return model; -} - - -Mesh::Material* -BinaryModelLoader::loadMaterial() -{ - Mesh::Material* material = new Mesh::Material(); - - material->diffuse = DefaultDiffuse; - material->specular = DefaultSpecular; - material->emissive = DefaultEmissive; - material->specularPower = DefaultSpecularPower; - material->opacity = DefaultOpacity; - - for (;;) - { - ModelFileToken tok = readToken(in); - switch (tok) - { - case CMOD_Diffuse: - if (!readTypeColor(in, material->diffuse)) - { - reportError("Incorrect type for diffuse color"); - delete material; - return NULL; - } - break; - - case CMOD_Specular: - if (!readTypeColor(in, material->specular)) - { - reportError("Incorrect type for specular color"); - delete material; - return NULL; - } - break; - - case CMOD_Emissive: - if (!readTypeColor(in, material->emissive)) - { - reportError("Incorrect type for emissive color"); - delete material; - return NULL; - } - break; - - case CMOD_SpecularPower: - if (!readTypeFloat1(in, material->specularPower)) - { - reportError("Float expected for specularPower"); - delete material; - return NULL; - } - break; - - case CMOD_Opacity: - if (!readTypeFloat1(in, material->opacity)) - { - reportError("Float expected for opacity"); - delete material; - return NULL; - } - break; - - case CMOD_Blend: - { - int16 blendMode = readInt16(in); - if (blendMode < 0 || blendMode >= Mesh::BlendMax) - { - reportError("Bad blend mode"); - delete material; - return NULL; - } - material->blend = (Mesh::BlendMode) blendMode; - } - break; - - case CMOD_Texture: - { - int16 texType = readInt16(in); - if (texType < 0 || texType >= Mesh::TextureSemanticMax) - { - reportError("Bad texture type"); - delete material; - return NULL; - } - - string texfile; - if (!readTypeString(in, texfile)) - { - reportError("String expected for texture filename"); - delete material; - return NULL; - } - - if (texfile.empty()) - { - reportError("Zero length texture name in material definition"); - delete material; - return NULL; - } - - ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(texfile, getTexturePath(), TextureInfo::WrapTexture)); - - material->maps[texType] = tex; - } - break; - - case CMOD_EndMaterial: - return material; - - default: - // Skip unrecognized tokens - if (!ignoreValue(in)) - { - delete material; - return NULL; - } - } // switch - } // for -} - - -Mesh::VertexDescription* -BinaryModelLoader::loadVertexDescription() -{ - if (readToken(in) != CMOD_VertexDesc) - { - reportError("Vertex description expected"); - return NULL; - } - - int maxAttributes = 16; - int nAttributes = 0; - uint32 offset = 0; - Mesh::VertexAttribute* attributes = new Mesh::VertexAttribute[maxAttributes]; - - for (;;) - { - int16 tok = readInt16(in); - - if (tok == CMOD_EndVertexDesc) - { - break; - } - else if (tok >= 0 && tok < Mesh::SemanticMax) - { - int16 fmt = readInt16(in); - if (fmt < 0 || fmt >= Mesh::FormatMax) - { - reportError("Invalid vertex attribute type"); - delete[] attributes; - return NULL; - } - else - { - if (nAttributes == maxAttributes) - { - reportError("Too many attributes in vertex description"); - delete[] attributes; - return NULL; - } - - attributes[nAttributes].semantic = - static_cast(tok); - attributes[nAttributes].format = - static_cast(fmt); - attributes[nAttributes].offset = offset; - - offset += Mesh::getVertexAttributeSize(attributes[nAttributes].format); - nAttributes++; - } - } - else - { - reportError("Invalid semantic in vertex description"); - delete[] attributes; - return NULL; - } - } - - if (nAttributes == 0) - { - reportError("Vertex definitition cannot be empty"); - delete[] attributes; - return NULL; - } - - Mesh::VertexDescription *vertexDesc = - new Mesh::VertexDescription(offset, nAttributes, attributes); - delete[] attributes; - return vertexDesc; -} - - -Mesh* -BinaryModelLoader::loadMesh() -{ - Mesh::VertexDescription* vertexDesc = loadVertexDescription(); - if (vertexDesc == NULL) - return NULL; - - uint32 vertexCount = 0; - char* vertexData = loadVertices(*vertexDesc, vertexCount); - if (vertexData == NULL) - { - delete vertexDesc; - return NULL; - } - - Mesh* mesh = new Mesh(); - mesh->setVertexDescription(*vertexDesc); - mesh->setVertices(vertexCount, vertexData); - delete vertexDesc; - - for (;;) - { - int16 tok = readInt16(in); - - if (tok == CMOD_EndMesh) - { - break; - } - else if (tok < 0 || tok >= Mesh::PrimitiveTypeMax) - { - reportError("Bad primitive group type"); - delete mesh; - return NULL; - } - - Mesh::PrimitiveGroupType type = - static_cast(tok); - uint32 materialIndex = readUint(in); - uint32 indexCount = readUint(in); - - uint32* indices = new uint32[indexCount]; - if (indices == NULL) - { - reportError("Not enough memory to hold indices"); - delete mesh; - return NULL; - } - - for (uint32 i = 0; i < indexCount; i++) - { - uint32 index = readUint(in); - if (index >= vertexCount) - { - reportError("Index out of range"); - delete indices; - delete mesh; - return NULL; - } - - indices[i] = index; - } - - mesh->addGroup(type, materialIndex, indexCount, indices); - } - - return mesh; -} - - -char* -BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc, - uint32& vertexCount) -{ - if (readToken(in) != CMOD_Vertices) - { - reportError("Vertex data expected"); - return NULL; - } - - vertexCount = readUint(in); - uint32 vertexDataSize = vertexDesc.stride * vertexCount; - char* vertexData = new char[vertexDataSize]; - if (vertexData == NULL) - { - reportError("Not enough memory to hold vertex data"); - return NULL; - } - - uint32 offset = 0; - - for (uint32 i = 0; i < vertexCount; i++, offset += vertexDesc.stride) - { - assert(offset < vertexDataSize); - for (uint32 attr = 0; attr < vertexDesc.nAttributes; attr++) - { - uint32 base = offset + vertexDesc.attributes[attr].offset; - Mesh::VertexAttributeFormat fmt = vertexDesc.attributes[attr].format; - /*int readCount = 0; Unused*/ - switch (fmt) - { - case Mesh::Float1: - reinterpret_cast(vertexData + base)[0] = readFloat(in); - break; - case Mesh::Float2: - reinterpret_cast(vertexData + base)[0] = readFloat(in); - reinterpret_cast(vertexData + base)[1] = readFloat(in); - break; - case Mesh::Float3: - reinterpret_cast(vertexData + base)[0] = readFloat(in); - reinterpret_cast(vertexData + base)[1] = readFloat(in); - reinterpret_cast(vertexData + base)[2] = readFloat(in); - break; - case Mesh::Float4: - reinterpret_cast(vertexData + base)[0] = readFloat(in); - reinterpret_cast(vertexData + base)[1] = readFloat(in); - reinterpret_cast(vertexData + base)[2] = readFloat(in); - reinterpret_cast(vertexData + base)[3] = readFloat(in); - break; - case Mesh::UByte4: - in.get(reinterpret_cast(vertexData + base), 4); - break; - default: - assert(0); - delete[] vertexData; - return NULL; - } - } - } - - return vertexData; -} - - - -/***** Binary writer *****/ - -BinaryModelWriter::BinaryModelWriter(ostream& _out) : - out(_out) -{ -} - - -BinaryModelWriter::~BinaryModelWriter() -{ -} - - -// Utility functions for writing binary values to a file -static void writeUint(ostream& out, uint32 val) -{ - LE_TO_CPU_INT32(val, val); - out.write(reinterpret_cast(&val), sizeof(uint32)); -} - -static void writeFloat(ostream& out, float val) -{ - LE_TO_CPU_FLOAT(val, val); - out.write(reinterpret_cast(&val), sizeof(float)); -} - -static void writeInt16(ostream& out, int16 val) -{ - LE_TO_CPU_INT16(val, val); - out.write(reinterpret_cast(&val), sizeof(int16)); -} - -static void writeToken(ostream& out, ModelFileToken val) -{ - writeInt16(out, static_cast(val)); -} - -static void writeType(ostream& out, ModelFileType val) -{ - writeInt16(out, static_cast(val)); -} - - -static void writeTypeFloat1(ostream& out, float f) -{ - writeType(out, CMOD_Float1); - writeFloat(out, f); -} - - -static void writeTypeColor(ostream& out, const Color& c) -{ - writeType(out, CMOD_Color); - writeFloat(out, c.red()); - writeFloat(out, c.green()); - writeFloat(out, c.blue()); -} - - -static void writeTypeString(ostream& out, const string& s) -{ - writeType(out, CMOD_String); - writeInt16(out, static_cast(s.length())); - out.write(s.c_str(), s.length()); -} - - -bool -BinaryModelWriter::write(const Model& model) -{ - out << CEL_MODEL_HEADER_BINARY; - - for (uint32 matIndex = 0; model.getMaterial(matIndex); matIndex++) - writeMaterial(*model.getMaterial(matIndex)); - - for (uint32 meshIndex = 0; model.getMesh(meshIndex); meshIndex++) - writeMesh(*model.getMesh(meshIndex)); - - return true; -} - - -void -BinaryModelWriter::writeGroup(const Mesh::PrimitiveGroup& group) -{ - writeInt16(out, static_cast(group.prim)); - writeUint(out, group.materialIndex); - writeUint(out, group.nIndices); - - // Print the indices, twelve per line - for (uint32 i = 0; i < group.nIndices; i++) - writeUint(out, group.indices[i]); -} - - -void -BinaryModelWriter::writeMesh(const Mesh& mesh) -{ - writeToken(out, CMOD_Mesh); - - writeVertexDescription(mesh.getVertexDescription()); - - writeVertices(mesh.getVertexData(), - mesh.getVertexCount(), - mesh.getVertexStride(), - mesh.getVertexDescription()); - - for (uint32 groupIndex = 0; mesh.getGroup(groupIndex); groupIndex++) - writeGroup(*mesh.getGroup(groupIndex)); - - writeToken(out, CMOD_EndMesh); -} - - -void -BinaryModelWriter::writeVertices(const void* vertexData, - uint32 nVertices, - uint32 stride, - const Mesh::VertexDescription& desc) -{ - const char* vertex = reinterpret_cast(vertexData); - - writeToken(out, CMOD_Vertices); - writeUint(out, nVertices); - - for (uint32 i = 0; i < nVertices; i++, vertex += stride) - { - for (uint32 attr = 0; attr < desc.nAttributes; attr++) - { - const char* cdata = vertex + desc.attributes[attr].offset; - const float* fdata = reinterpret_cast(cdata); - - switch (desc.attributes[attr].format) - { - case Mesh::Float1: - writeFloat(out, fdata[0]); - break; - case Mesh::Float2: - writeFloat(out, fdata[0]); - writeFloat(out, fdata[1]); - break; - case Mesh::Float3: - writeFloat(out, fdata[0]); - writeFloat(out, fdata[1]); - writeFloat(out, fdata[2]); - break; - case Mesh::Float4: - writeFloat(out, fdata[0]); - writeFloat(out, fdata[1]); - writeFloat(out, fdata[2]); - writeFloat(out, fdata[3]); - break; - case Mesh::UByte4: - out.write(cdata, 4); - break; - default: - assert(0); - break; - } - } - } -} - - -void -BinaryModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc) -{ - writeToken(out, CMOD_VertexDesc); - - for (uint32 attr = 0; attr < desc.nAttributes; attr++) - { - writeInt16(out, static_cast(desc.attributes[attr].semantic)); - writeInt16(out, static_cast(desc.attributes[attr].format)); - } - - writeToken(out, CMOD_EndVertexDesc); -} - - -void -BinaryModelWriter::writeMaterial(const Mesh::Material& material) -{ - writeToken(out, CMOD_Material); - - if (material.diffuse != DefaultDiffuse) - { - writeToken(out, CMOD_Diffuse); - writeTypeColor(out, material.diffuse); - } - - if (material.emissive != DefaultEmissive) - { - writeToken(out, CMOD_Emissive); - writeTypeColor(out, material.emissive); - } - - if (material.specular != DefaultSpecular) - { - writeToken(out, CMOD_Specular); - writeTypeColor(out, material.specular); - } - - if (material.specularPower != DefaultSpecularPower) - { - writeToken(out, CMOD_SpecularPower); - writeTypeFloat1(out, material.specularPower); - } - - if (material.opacity != DefaultOpacity) - { - writeToken(out, CMOD_Opacity); - writeTypeFloat1(out, material.opacity); - } - - if (material.blend != DefaultBlend) - { - writeToken(out, CMOD_Blend); - writeInt16(out, (int16) material.blend); - } - - for (int i = 0; i < Mesh::TextureSemanticMax; i++) - { - if (material.maps[i] != InvalidResource) - { - const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.maps[i]); - if (texInfo != NULL) - { - writeToken(out, CMOD_Texture); - writeInt16(out, (int16) i); - writeTypeString(out, texInfo->source); - } - } - } -#if 0 - if (material.tex1 != InvalidResource) - { - const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.tex1); - if (texInfo != NULL) - { - writeToken(out, CMOD_Texture1); - writeTypeString(out, texInfo->source); - } - } -#endif - - writeToken(out, CMOD_EndMaterial); -} Index: src/celengine/shadermanager.cpp =================================================================== --- src/celengine/shadermanager.cpp (revision 4952) +++ src/celengine/shadermanager.cpp (working copy) @@ -26,6 +26,7 @@ // GLSL on Mac OS X appears to have a bug that precludes us from using structs // #define USE_GLSL_STRUCTS +#define POINT_FADE 0 ShaderManager g_ShaderManager; @@ -3318,6 +3319,15 @@ light.color.blue()) * light.irradiance; lights[i].direction = light.direction_obj; + // Include a phase-based normalization factor to prevent planets from appearing + // too dim when rendered with non-Lambertian photometric functions. + float cosPhaseAngle = light.direction_obj.dot(ls.eyeDir_obj); + if (props.lightModel == ShaderProperties::LunarLambertModel) + { + float photometricNormFactor = std::max(1.0f, 1.0f + cosPhaseAngle * 0.5f); + lightColor *= photometricNormFactor; + } + if (props.usesShadows() || props.usesFragmentLighting() || props.lightModel == ShaderProperties::RingIllumModel) Index: src/celengine/spheremesh.h =================================================================== --- src/celengine/spheremesh.h (revision 4952) +++ src/celengine/spheremesh.h (working copy) @@ -12,12 +12,15 @@ #define _CELENGINE_SPHEREMESH_H_ // IMPORTANT: This file is a relic from the early days of Celestia. -// It's sole function now is to handle the now-deprecated .cms mesh files; +// Its sole function now is to handle the now-deprecated .cms mesh files; // it will eventually be removed from Celestia. -#include #include +#include +using namespace cmod; + + /*! The SphereMesh class is used to generate displacement mapped * spheres when loading the now-deprecated .cms geometry files. * It remains in the Celestia code base for backward compatibility, Index: src/celengine/meshmanager.cpp =================================================================== --- src/celengine/meshmanager.cpp (revision 4952) +++ src/celengine/meshmanager.cpp (working copy) @@ -1,6 +1,7 @@ // meshmanager.cpp // -// Copyright (C) 2001-2006 Chris Laurel +// Copyright (C) 2001-2010, Celestia Development Team +// Original version by Chris Laurel // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -10,19 +11,6 @@ // Experimental particle system support #define PARTICLE_SYSTEM 0 -#include -#include -#include - -#include "celestia.h" -#include -#include -#include -#include -#include -#include - -#include "modelfile.h" #if PARTICLE_SYSTEM #include "particlesystem.h" #include "particlesystemfile.h" @@ -32,7 +20,24 @@ #include "spheremesh.h" #include "texmanager.h" #include "meshmanager.h" +#include "modelgeometry.h" +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + + +using namespace cmod; using namespace Eigen; using namespace std; @@ -45,6 +50,27 @@ static const char UniqueSuffixChar = '!'; +class CelestiaTextureLoader : public cmod::TextureLoader +{ +public: + CelestiaTextureLoader(const std::string& texturePath) : + m_texturePath(texturePath) + { + } + + ~CelestiaTextureLoader() {} + + Material::TextureResource* loadTexture(const std::string& name) + { + ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(name, m_texturePath, TextureInfo::WrapTexture)); + return new CelestiaTextureResource(tex); + } + +private: + std::string m_texturePath; +}; + + GeometryManager* GetGeometryManager() { if (geometryManager == NULL) @@ -109,7 +135,9 @@ ifstream in(filename.c_str(), ios::binary); if (in.good()) { - model = LoadModel(in, path); + CelestiaTextureLoader textureLoader(path); + + model = LoadModel(in, &textureLoader); if (model != NULL) { if (isNormalized) @@ -171,7 +199,7 @@ cerr << _("Error loading model '") << filename << "'\n"; } - return model; + return new ModelGeometry(model); } @@ -427,8 +455,6 @@ // current equation is just a guess at the mapping that // 3DS actually uses. shininess = (float) pow(2.0, 1.0 + 0.1 * shininess); - //shininess = 2.0f + shininess; - //clog << materialName << ": shininess=" << shininess << ", color=" << specular.red << "," << specular.green << "," << specular.blue << '\n'; if (shininess > 128.0f) shininess = 128.0f; vl->setShininess(shininess); @@ -527,6 +553,10 @@ return mesh; } +Material::Color toMaterialColor(Color c) +{ + return Material::Color(c.red(), c.green(), c.blue()); +} static Model* Convert3DSModel(const M3DScene& scene, const string& texPath) @@ -551,12 +581,12 @@ Mesh* mesh = ConvertVertexListToMesh(vlist, texPath, materialIndex); // Convert the vertex list material - Mesh::Material* material = new Mesh::Material(); - material->diffuse = vlist->getDiffuseColor(); - material->specular = vlist->getSpecularColor(); + Material* material = new Material(); + material->diffuse = toMaterialColor(vlist->getDiffuseColor()); + material->specular = toMaterialColor(vlist->getSpecularColor()); material->specularPower = vlist->getShininess(); material->opacity = vlist->getDiffuseColor().alpha(); - material->maps[Mesh::DiffuseMap] = vlist->getTexture(); + material->maps[Material::DiffuseMap] = new CelestiaTextureResource(vlist->getTexture()); model->addMaterial(material); materialIndex++; Index: src/celengine/astro.cpp =================================================================== --- src/celengine/astro.cpp (revision 4952) +++ src/celengine/astro.cpp (working copy) @@ -185,76 +185,6 @@ return absMagToLum(appToAbsMag(mag, lyrs)); } -float astro::lightYearsToParsecs(float ly) -{ - return ly / (float) LY_PER_PARSEC; -} - -double astro::lightYearsToParsecs(double ly) -{ - return ly / (double) LY_PER_PARSEC; -} - -float astro::parsecsToLightYears(float pc) -{ - return pc * (float) LY_PER_PARSEC; -} - -double astro::parsecsToLightYears(double pc) -{ - return pc * (double) LY_PER_PARSEC; -} - -float astro::lightYearsToKilometers(float ly) -{ - return ly * (float) KM_PER_LY; -} - -double astro::lightYearsToKilometers(double ly) -{ - return ly * KM_PER_LY; -} - -float astro::kilometersToLightYears(float km) -{ - return km / (float) KM_PER_LY; -} - -double astro::kilometersToLightYears(double km) -{ - return km / KM_PER_LY; -} - -float astro::lightYearsToAU(float ly) -{ - return ly * (float) AU_PER_LY; -} - -double astro::lightYearsToAU(double ly) -{ - return ly * AU_PER_LY; -} - -float astro::AUtoKilometers(float au) -{ - return au * (float) KM_PER_AU; -} - -double astro::AUtoKilometers(double au) -{ - return au * (double) KM_PER_AU; -} - -float astro::kilometersToAU(float km) -{ - return km / (float) KM_PER_AU; -} - -double astro::kilometersToAU(double km) -{ - return km / KM_PER_AU; -} - double astro::secondsToJulianDate(double sec) { return sec / SECONDS_PER_DAY; Index: src/celengine/simulation.h =================================================================== --- src/celengine/simulation.h (revision 4952) +++ src/celengine/simulation.h (working copy) @@ -11,7 +11,6 @@ #define _CELENGINE_SIMULATION_H_ #include -#include #include #include #include Index: src/celmodel/model.cpp =================================================================== --- src/celmodel/model.cpp (revision 0) +++ src/celmodel/model.cpp (working copy) @@ -1,6 +1,7 @@ // model.cpp // -// Copyright (C) 2004-2006, Chris Laurel +// Copyright (C) 2004-2010, Celestia Development Team +// Original version by Chris Laurel // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -8,69 +9,37 @@ // of the License, or (at your option) any later version. #include "model.h" -#include "rendcontext.h" -#include "texmanager.h" #include #include #include +using namespace cmod; using namespace Eigen; using namespace std; -#if 0 -static GLenum GLPrimitiveModes[MaxPrimitiveType] = -{ - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN, - GL_LINES, - GL_LINE_STRIP, - GL_POINTS -}; -#endif - -#if 0 -static size_t VertexAttributeFormatSizes[Mesh::FormatMax] = -{ - 4, // Float1 - 8, // Float2 - 12, // Float3 - 16, // Float4, - 4, // UByte4 -}; -#endif - - Model::Model() : opaque(true), normalized(false) { - for (int i = 0; i < Mesh::TextureSemanticMax; i++) + for (int i = 0; i < Material::TextureSemanticMax; i++) + { textureUsage[i] = false; + } } Model::~Model() { + for (vector::iterator iter = meshes.begin(); iter != meshes.end(); iter++) { - for (vector::iterator iter = meshes.begin(); - iter != meshes.end(); iter++) - delete *iter; + delete *iter; } - -#if 0 - { - for (vector::iterator iter = materials.begin(); - iter != materials.end(); iter++) - delete *iter; - } -#endif } -const Mesh::Material* -Model::getMaterial(uint32 index) const +const Material* +Model::getMaterial(unsigned int index) const { if (index < materials.size()) return materials[index]; @@ -79,18 +48,20 @@ } -uint32 -Model::addMaterial(const Mesh::Material* m) +unsigned int +Model::addMaterial(const Material* m) { // Update the texture map usage information for the model. Since // the material being added isn't necessarily used by a mesh within // the model, we could potentially end up with false positives--this // won't cause any rendering troubles, but could hurt performance // if it forces multipass rendering when it's not required. - for (int i = 0; i < Mesh::TextureSemanticMax; i++) + for (int i = 0; i < Material::TextureSemanticMax; i++) { - if (m->maps[i] != InvalidResource) + if (m->maps[i]) + { textureUsage[i] = true; + } } materials.push_back(m); @@ -98,17 +69,17 @@ } -uint32 +unsigned int Model::getMaterialCount() const { return materials.size(); } -uint32 +unsigned int Model::getVertexCount() const { - uint32 count = 0; + unsigned int count = 0; for (vector::const_iterator iter = meshes.begin(); iter != meshes.end(); iter++) @@ -120,10 +91,10 @@ } -uint32 +unsigned int Model::getPrimitiveCount() const { - uint32 count = 0; + unsigned int count = 0; for (vector::const_iterator iter = meshes.begin(); iter != meshes.end(); iter++) @@ -135,8 +106,15 @@ } +unsigned int +Model::getMeshCount() const +{ + return meshes.size(); +} + + Mesh* -Model::getMesh(uint32 index) const +Model::getMesh(unsigned int index) const { if (index < meshes.size()) return meshes[index]; @@ -145,7 +123,7 @@ } -uint32 +unsigned int Model::addMesh(Mesh* m) { meshes.push_back(m); @@ -154,7 +132,7 @@ bool -Model::pick(const Ray3d& r, double& distance) const +Model::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, double& distance) const { double maxDistance = 1.0e30; double closest = maxDistance; @@ -163,8 +141,10 @@ iter != meshes.end(); iter++) { double d = maxDistance; - if ((*iter)->pick(r, d) && d < closest) + if ((*iter)->pick(rayOrigin, rayDirection, d) && d < closest) + { closest = d; + } } if (closest != maxDistance) @@ -179,6 +159,7 @@ } +#if 0 /*! Render the model; the time parameter is ignored right now * since this class doesn't currently support animation. */ @@ -191,6 +172,7 @@ (*iter)->render(materials, rc); } } +#endif /*! Translate and scale a model. The transformation applied to @@ -224,7 +206,7 @@ static bool -operator<(const Color& c0, const Color& c1) +operator<(const Material::Color& c0, const Material::Color& c1) { if (c0.red() < c1.red()) return true; @@ -243,7 +225,7 @@ // Define an ordering for materials; required for elimination of duplicate // materials. static bool -operator<(const Mesh::Material& m0, const Mesh::Material& m1) +operator<(const Material& m0, const Material& m1) { // Checking opacity first and doing it backwards is deliberate. It means // that after sorting, translucent materials will end up with higher @@ -283,7 +265,7 @@ else if (m0.specularPower > m1.specularPower) return false; - for (unsigned int i = 0; i < Mesh::TextureSemanticMax; i++) + for (unsigned int i = 0; i < Material::TextureSemanticMax; i++) { if (m0.maps[i] < m1.maps[i]) return true; @@ -301,7 +283,7 @@ struct IndexedMaterial { int originalIndex; - const Mesh::Material* material; + const Material* material; }; @@ -340,9 +322,9 @@ // Sort the indexed materials so that we can uniquify them sort(indexedMaterials.begin(), indexedMaterials.end()); - vector uniqueMaterials; - vector materialMap(materials.size()); - vector duplicateMaterials; + vector uniqueMaterials; + vector materialMap(materials.size()); + vector duplicateMaterials; // From the sorted material list construct the list of unique materials // and a map to convert old material indices into indices that can be @@ -371,7 +353,7 @@ (*iter)->remapMaterials(materialMap); } - vector::const_iterator dupIter; + vector::const_iterator dupIter; for (dupIter = duplicateMaterials.begin(); dupIter != duplicateMaterials.end(); ++dupIter) { @@ -388,7 +370,7 @@ for (unsigned int i = 0; i < materials.size(); i++) { if ((materials[i]->opacity > 0.01f && materials[i]->opacity < 1.0f) || - materials[i]->blend == Mesh::AdditiveBlend) + materials[i]->blend == Material::AdditiveBlend) { opaque = false; return; @@ -400,7 +382,7 @@ bool -Model::usesTextureType(Mesh::TextureSemantic t) const +Model::usesTextureType(Material::TextureSemantic t) const { return textureUsage[static_cast(t)]; } @@ -432,7 +414,7 @@ // Look at the material used by last primitive group in the mesh for the // opacity of the whole model. This is a very crude way to check the opacity // of a mesh and misses many cases. -static uint32 +static unsigned int getMeshMaterialIndex(const Mesh& mesh) { if (mesh.getGroupCount() == 0) @@ -468,21 +450,23 @@ } -void -Model::loadTextures() -{ - for (vector::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]); - } -} +#if 0 +void +Model::loadTextures() +{ + for (vector::const_iterator iter = materials.begin(); + iter != materials.end(); iter++) + { + const Mesh::Material* m = *iter; + + if (m->maps[Material::DiffuseMap] != InvalidResource) + GetTextureManager()->find(m->maps[Material::DiffuseMap]); + if (m->maps[Material::NormalMap] != InvalidResource) + GetTextureManager()->find(m->maps[Material::NormalMap]); + if (m->maps[Material::SpecularMap] != InvalidResource) + GetTextureManager()->find(m->maps[Material::SpecularMap]); + if (m->maps[Material::EmissiveMap] != InvalidResource) + GetTextureManager()->find(m->maps[Material::EmissiveMap]); + } +} +#endif Index: src/celmodel/modelfile.cpp =================================================================== --- src/celmodel/modelfile.cpp (revision 0) +++ src/celmodel/modelfile.cpp (working copy) @@ -1,6 +1,7 @@ // modelfile.cpp // -// Copyright (C) 2004, Chris Laurel +// Copyright (C) 2004-2010, Celestia Development Team +// Original version by Chris Laurel // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -8,27 +9,646 @@ // of the License, or (at your option) any later version. #include "modelfile.h" -#include "tokenizer.h" -#include "texmanager.h" +#include #include #include #include #include #include + +using namespace cmod; using namespace std; - // Material default values -static Color DefaultDiffuse(0.0f, 0.0f, 0.0f); -static Color DefaultSpecular(0.0f, 0.0f, 0.0f); -static Color DefaultEmissive(0.0f, 0.0f, 0.0f); +static Material::Color DefaultDiffuse(0.0f, 0.0f, 0.0f); +static Material::Color DefaultSpecular(0.0f, 0.0f, 0.0f); +static Material::Color DefaultEmissive(0.0f, 0.0f, 0.0f); static float DefaultSpecularPower = 1.0f; static float DefaultOpacity = 1.0f; -static Mesh::BlendMode DefaultBlend = Mesh::NormalBlend; +static Material::BlendMode DefaultBlend = Material::NormalBlend; + +namespace cmod +{ + +class Token +{ +public: + enum TokenType + { + Name, + String, + Number, + End, + Invalid + }; + + Token() : + m_type(Invalid), + m_numberValue(0.0) + { + } + + Token(const Token& other) : + m_type(other.m_type), + m_numberValue(other.m_numberValue), + m_stringValue(other.m_stringValue) + { + } + + Token& operator=(const Token& other) + { + m_type = other.m_type; + m_numberValue = other.m_numberValue; + m_stringValue = other.m_stringValue; + return *this; + } + + bool operator==(const Token& other) const + { + if (m_type == other.m_type) + { + switch (m_type) + { + case Name: + case String: + return m_stringValue == other.m_stringValue; + case Number: + return m_numberValue == other.m_numberValue; + case End: + case Invalid: + return true; + default: + return false; + } + } + else + { + return false; + } + } + + bool operator!=(const Token& other) const + { + return !(*this == other); + } + + ~Token() + { + } + + TokenType type() const + { + return m_type; + } + + bool isValid() const + { + return m_type != Invalid; + } + + bool isNumber() const + { + return m_type == Number; + } + + bool isInteger() const + { + return m_type == Number; + } + + bool isName() const + { + return m_type == Name; + } + + bool isString() const + { + return m_type == String; + } + + double numberValue() const + { + assert(type() == Number); + if (type() == Number) + { + return m_numberValue; + } + else + { + return 0.0; + } + } + + int integerValue() const + { + assert(type() == Number); + //assert(std::floor(m_numberValue) == m_numberValue); + + if (type() == Number) + { + return (int) m_numberValue; + } + else + { + return 0; + } + } + + std::string stringValue() const + { + if (type() == Name || type() == String) + { + return m_stringValue; + } + else + { + return string(); + } + } + +public: + static Token NumberToken(double value) + { + Token token; + token.m_type = Number; + token.m_numberValue = value; + return token; + } + + static Token NameToken(const string& value) + { + Token token; + token.m_type = Name; + token.m_stringValue = value; + return token; + } + + static Token StringToken(const string& value) + { + Token token; + token.m_type = String; + token.m_stringValue = value; + return token; + } + + static Token EndToken() + { + Token token; + token.m_type = End; + return token; + } + +private: + TokenType m_type; + double m_numberValue; + string m_stringValue; +}; + + +class TokenStream +{ +public: + TokenStream(istream* in) : + m_in(in), + m_currentToken(), + m_pushedBack(false), + m_lineNumber(1), + m_parseError(false), + m_nextChar(' ') + { + } + + bool issep(char c) + { + return !isdigit(c) && !isalpha(c) && c != '.'; + } + + void syntaxError(const std::string& message) + { + cerr << message << '\n'; + m_parseError = true; + } + + Token nextToken(); + + Token currentToken() const + { + return m_currentToken; + } + + void pushBack() + { + m_pushedBack = true; + } + + int readChar() + { + int c = (int) m_in->get(); + if (c == '\n') + { + m_lineNumber++; + } + + return c; + } + + int getLineNumber() const + { + return m_lineNumber; + } + + bool hasError() const + { + return m_parseError; + } + +private: + double numberFromParts(double integerValue, double fractionValue, double fracExp, + double exponentValue, double exponentSign, + double sign) const + { + double x = integerValue + fractionValue / fracExp; + if (exponentValue != 0) + { + x *= pow(10.0, exponentValue * exponentSign); + } + + return x * sign; + } + + enum State + { + StartState = 0, + NameState = 1, + NumberState = 2, + FractionState = 3, + ExponentState = 4, + ExponentFirstState = 5, + DotState = 6, + CommentState = 7, + StringState = 8, + ErrorState = 9, + StringEscapeState = 10, + }; + +private: + istream* m_in; + Token m_currentToken; + bool m_pushedBack; + int m_lineNumber; + bool m_parseError; + int m_nextChar; +}; + +} // namespace + + + +Token TokenStream::nextToken() +{ + State state = StartState; + + if (m_pushedBack) + { + m_pushedBack = false; + return m_currentToken; + } + + if (m_currentToken.type() == Token::End) + { + // Already at end of stream + return m_currentToken; + } + + double integerValue = 0; + double fractionValue = 0; + double sign = 1; + double fracExp = 1; + double exponentValue = 0; + double exponentSign = 1; + + Token newToken; + + string textValue; + + while (!hasError() && !newToken.isValid()) + { + switch (state) + { + case StartState: + if (isspace(m_nextChar)) + { + state = StartState; + } + else if (isdigit(m_nextChar)) + { + state = NumberState; + integerValue = m_nextChar - (int) '0'; + } + else if (m_nextChar == '-') + { + state = NumberState; + sign = -1; + integerValue = 0; + } + else if (m_nextChar == '+') + { + state = NumberState; + sign = +1; + integerValue = 0; + } + else if (m_nextChar == '.') + { + state = FractionState; + sign = +1; + integerValue = 0; + } + else if (isalpha(m_nextChar) || m_nextChar == '_') + { + state = NameState; + textValue += (char) m_nextChar; + } + else if (m_nextChar == '#') + { + state = CommentState; + } + else if (m_nextChar == '"') + { + state = StringState; + } + else if (m_nextChar == -1) + { + newToken = Token::EndToken(); + } + else + { + syntaxError("Bad character in stream"); + } + break; + + case NameState: + if (isalpha(m_nextChar) || isdigit(m_nextChar) || m_nextChar == '_') + { + state = NameState; + textValue += (char) m_nextChar; + } + else + { + newToken = Token::NameToken(textValue); + } + break; + + case CommentState: + if (m_nextChar == '\n' || m_nextChar == '\r' || m_nextChar == char_traits::eof()) + { + state = StartState; + } + break; + + case StringState: + if (m_nextChar == '"') + { + newToken = Token::StringToken(textValue); + m_nextChar = readChar(); + } + else if (m_nextChar == '\\') + { + state = StringEscapeState; + } + else if (m_nextChar == char_traits::eof()) + { + syntaxError("Unterminated string"); + } + else + { + state = StringState; + textValue += (char) m_nextChar; + } + break; + + case StringEscapeState: + if (m_nextChar == '\\') + { + textValue += '\\'; + state = StringState; + } + else if (m_nextChar == 'n') + { + textValue += '\n'; + state = StringState; + } + else if (m_nextChar == '"') + { + textValue += '"'; + state = StringState; + } + else + { + syntaxError("Unknown escape code in string"); + state = StringState; + } + break; + + case NumberState: + if (isdigit(m_nextChar)) + { + state = NumberState; + integerValue = integerValue * 10 + m_nextChar - (int) '0'; + } + else if (m_nextChar == '.') + { + state = FractionState; + } + else if (m_nextChar == 'e' || m_nextChar == 'E') + { + state = ExponentFirstState; + } + else if (issep(m_nextChar)) + { + double x = numberFromParts(integerValue, fractionValue, fracExp, exponentValue, exponentSign, sign); + newToken = Token::NumberToken(x); + } + else + { + syntaxError("Bad character in number"); + } + break; + + case FractionState: + if (isdigit(m_nextChar)) + { + state = FractionState; + fractionValue = fractionValue * 10 + m_nextChar - (int) '0'; + fracExp *= 10; + } + else if (m_nextChar == 'e' || m_nextChar == 'E') + { + state = ExponentFirstState; + } + else if (issep(m_nextChar)) + { + double x = numberFromParts(integerValue, fractionValue, fracExp, exponentValue, exponentSign, sign); + newToken = Token::NumberToken(x); + } + else + { + syntaxError("Bad character in number"); + } + break; + + case ExponentFirstState: + if (isdigit(m_nextChar)) + { + state = ExponentState; + exponentValue = (int) m_nextChar - (int) '0'; + } + else if (m_nextChar == '-') + { + state = ExponentState; + exponentSign = -1; + } + else if (m_nextChar == '+') + { + state = ExponentState; + } + else + { + state = ErrorState; + syntaxError("Bad character in number"); + } + break; + + case ExponentState: + if (isdigit(m_nextChar)) + { + state = ExponentState; + exponentValue = exponentValue * 10 + (int) m_nextChar - (int) '0'; + } + else if (issep(m_nextChar)) + { + double x = numberFromParts(integerValue, fractionValue, fracExp, exponentValue, exponentSign, sign); + newToken = Token::NumberToken(x); + } + else + { + state = ErrorState; + syntaxError("Bad character in number"); + } + break; + + case DotState: + if (isdigit(m_nextChar)) + { + state = FractionState; + fractionValue = fractionValue * 10 + (int) m_nextChar - (int) '0'; + fracExp = 10; + } + else + { + state = ErrorState; + syntaxError("'.' in stupid place"); + } + break; + + case ErrorState: + break; // Prevent GCC4 warnings; do nothing + + } // Switch + + if (!hasError() && !newToken.isValid()) + { + m_nextChar = readChar(); + } + } + + m_currentToken = newToken; + + return newToken; +} + + +#if 0 +class BinaryInputStream +{ +public: + BinaryInputStream(istream* in) : + m_in(in) + { + } + +private: + istream* m_in; +}; + + +class BinaryOutputStream +{ +public: + BinaryOutputStream(ostream* out) : + m_out(out) + { + } + + void writeUint32(unsigned int i); + void writeInt16(int i); + void writeFloat(float f); + + void writeString(const std::string s) + { + writeInt16(static_cast(s.length())); + m_out->write(s.c_str(), s.length()); + } + +private: + ostream* m_out; +}; + + +class CmodBinaryOutputStream : public BinaryOuputStream +{ +public: + CmodBinaryOuputStream(ostream* out) : + BinaryOutputStream(out) + { + } + + void writeToken(ModelFileToken val) + { + writeInt16((int) val); + } + + void writeType(ModelFileType val) + { + writeInt16((int) val); + } + + void writeTypeFloat1(float f) + { + writeType(CMOD_Float1); + writeFloat(f); + } + + void writeTypeColor(const Material::Color& c) + { + writeType(CMOD_Color); + writeFloat(c.red); + writeFloat(c.green); + writeFloat(c.blue); + } + + void writeTypeString(const string& s) + { + writeType(out, CMOD_String); + writeString(s); + } +}; +#endif + + /*! This is an approximate Backus Naur form for the contents of ASCII cmod files. For brevity, the categories <unsigned_int> and <float> aren't @@ -107,17 +727,27 @@ virtual Model* load(); virtual void reportError(const string&); - Mesh::Material* loadMaterial(); + Material* loadMaterial(); Mesh::VertexDescription* loadVertexDescription(); Mesh* loadMesh(); char* loadVertices(const Mesh::VertexDescription& vertexDesc, - uint32& vertexCount); + unsigned int& vertexCount); private: - Tokenizer tok; + TokenStream tok; }; +// Standard tokens for ASCII model loader +static Token MeshToken = Token::NameToken("mesh"); +static Token EndMeshToken = Token::NameToken("end_mesh"); +static Token VertexDescToken = Token::NameToken("vertexdesc"); +static Token EndVertexDescToken = Token::NameToken("end_vertexdesc"); +static Token VerticesToken = Token::NameToken("vertices"); +static Token MaterialToken = Token::NameToken("material"); +static Token EndMaterialToken = Token::NameToken("end_material"); + + class AsciiModelWriter : public ModelWriter { public: @@ -128,12 +758,12 @@ private: void writeMesh(const Mesh&); - void writeMaterial(const Mesh::Material&); + void writeMaterial(const Material&); void writeGroup(const Mesh::PrimitiveGroup&); void writeVertexDescription(const Mesh::VertexDescription&); void writeVertices(const void* vertexData, - uint32 nVertices, - uint32 stride, + unsigned int nVertices, + unsigned int stride, const Mesh::VertexDescription& desc); ostream& out; @@ -149,11 +779,11 @@ virtual Model* load(); virtual void reportError(const string&); - Mesh::Material* loadMaterial(); + Material* loadMaterial(); Mesh::VertexDescription* loadVertexDescription(); Mesh* loadMesh(); char* loadVertices(const Mesh::VertexDescription& vertexDesc, - uint32& vertexCount); + unsigned int& vertexCount); private: istream& in; @@ -170,12 +800,12 @@ private: void writeMesh(const Mesh&); - void writeMaterial(const Mesh::Material&); + void writeMaterial(const Material&); void writeGroup(const Mesh::PrimitiveGroup&); void writeVertexDescription(const Mesh::VertexDescription&); void writeVertices(const void* vertexData, - uint32 nVertices, - uint32 stride, + unsigned int nVertices, + unsigned int stride, const Mesh::VertexDescription& desc); ostream& out; @@ -207,36 +837,32 @@ void -ModelLoader::setTexturePath(const string& _texPath) +ModelLoader::setTextureLoader(TextureLoader* _textureLoader) { - texPath = _texPath; + textureLoader = _textureLoader; } -const string& -ModelLoader::getTexturePath() const +TextureLoader* +ModelLoader::getTextureLoader() const { - return texPath; + return textureLoader; } -Model* LoadModel(istream& in) +Model* cmod::LoadModel(istream& in, TextureLoader* textureLoader) { - return LoadModel(in, ""); -} - - -Model* LoadModel(istream& in, const string& texPath) -{ ModelLoader* loader = ModelLoader::OpenModel(in); if (loader == NULL) return NULL; - loader->setTexturePath(texPath); + loader->setTextureLoader(textureLoader); Model* model = loader->load(); if (model == NULL) + { cerr << "Error in model file: " << loader->getErrorMessage() << '\n'; + } delete loader; @@ -267,7 +893,8 @@ } -bool SaveModelAscii(const Model* model, std::ostream& out) +bool +cmod::SaveModelAscii(const Model* model, std::ostream& out) { if (model == NULL) return false; @@ -278,7 +905,8 @@ } -bool SaveModelBinary(const Model* model, std::ostream& out) +bool +cmod::SaveModelBinary(const Model* model, std::ostream& out) { if (model == NULL) return false; @@ -309,17 +937,16 @@ } -Mesh::Material* +Material* AsciiModelLoader::loadMaterial() { - if (tok.nextToken() != Tokenizer::TokenName || - tok.getNameValue() != "material") + if (tok.nextToken() != MaterialToken) { reportError("Material definition expected"); return NULL; } - Mesh::Material* material = new Mesh::Material(); + Material* material = new Material(); material->diffuse = DefaultDiffuse; material->specular = DefaultSpecular; @@ -327,41 +954,52 @@ material->specularPower = DefaultSpecularPower; material->opacity = DefaultOpacity; - while (tok.nextToken() == Tokenizer::TokenName && - tok.getNameValue() != "end_material") + while (tok.nextToken().isName() && tok.currentToken() != EndMaterialToken) { - string property = tok.getNameValue(); - Mesh::TextureSemantic texType = Mesh::parseTextureSemantic(property); + string property = tok.currentToken().stringValue(); + Material::TextureSemantic texType = Mesh::parseTextureSemantic(property); - if (texType != Mesh::InvalidTextureSemantic) + if (texType != Material::InvalidTextureSemantic) { - if (tok.nextToken() != Tokenizer::TokenString) + Token t = tok.nextToken(); + if (t.type() != Token::String) { reportError("Texture name expected"); delete material; return NULL; } - ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(tok.getStringValue(), getTexturePath(), TextureInfo::WrapTexture)); + string textureName = t.stringValue(); + Material::TextureResource* tex = NULL; + if (getTextureLoader()) + { + getTextureLoader()->loadTexture(textureName); + } + else + { + tex = new Material::DefaultTextureResource(textureName); + } + material->maps[texType] = tex; } else if (property == "blend") { - Mesh::BlendMode blendMode = Mesh::InvalidBlend; + Material::BlendMode blendMode = Material::InvalidBlend; - if (tok.nextToken() == Tokenizer::TokenName) + Token t = tok.nextToken(); + if (t.isName()) { - string blendModeName = tok.getNameValue(); + string blendModeName = tok.currentToken().stringValue(); if (blendModeName == "normal") - blendMode = Mesh::NormalBlend; + blendMode = Material::NormalBlend; else if (blendModeName == "add") - blendMode = Mesh::AdditiveBlend; + blendMode = Material::AdditiveBlend; else if (blendModeName == "premultiplied") - blendMode = Mesh::PremultipliedAlphaBlend; + blendMode = Material::PremultipliedAlphaBlend; } - if (blendMode == Mesh::InvalidBlend) + if (blendMode == Material::InvalidBlend) { reportError("Bad blend mode in material"); delete material; @@ -377,37 +1015,52 @@ double data[3]; int nValues = 3; if (property == "specpower" || property == "opacity") + { nValues = 1; + } for (int i = 0; i < nValues; i++) { - if (tok.nextToken() != Tokenizer::TokenNumber) + Token t = tok.nextToken(); + if (t.type() != Token::Number) { reportError("Bad property value in material"); delete material; return NULL; } - data[i] = tok.getNumberValue(); + data[i] = t.numberValue(); } - Color colorVal; + Material::Color colorVal; if (nValues == 3) - colorVal = Color((float) data[0], (float) data[1], (float) data[2]); + { + colorVal = Material::Color((float) data[0], (float) data[1], (float) data[2]); + } if (property == "diffuse") + { material->diffuse = colorVal; + } else if (property == "specular") + { material->specular = colorVal; + } else if (property == "emissive") + { material->emissive = colorVal; + } else if (property == "opacity") + { material->opacity = (float) data[0]; + } else if (property == "specpower") + { material->specularPower = (float) data[0]; + } } } - if (tok.getTokenType() != Tokenizer::TokenName) + if (tok.currentToken().type() != Token::Name) { delete material; return NULL; @@ -422,8 +1075,7 @@ Mesh::VertexDescription* AsciiModelLoader::loadVertexDescription() { - if (tok.nextToken() != Tokenizer::TokenName || - tok.getNameValue() != "vertexdesc") + if (tok.nextToken() != VertexDescToken) { reportError("Vertex description expected"); return NULL; @@ -431,11 +1083,10 @@ int maxAttributes = 16; int nAttributes = 0; - uint32 offset = 0; + unsigned int offset = 0; Mesh::VertexAttribute* attributes = new Mesh::VertexAttribute[maxAttributes]; - while (tok.nextToken() == Tokenizer::TokenName && - tok.getNameValue() != "end_vertexdesc") + while (tok.nextToken().isName() && tok.currentToken() != EndVertexDescToken) { string semanticName; string formatName; @@ -450,11 +1101,11 @@ return NULL; } - semanticName = tok.getNameValue(); + semanticName = tok.currentToken().stringValue(); - if (tok.nextToken() == Tokenizer::TokenName) + if (tok.nextToken().isName()) { - formatName = tok.getNameValue(); + formatName = tok.currentToken().stringValue(); valid = true; } @@ -493,7 +1144,7 @@ nAttributes++; } - if (tok.getTokenType() != Tokenizer::TokenName) + if (tok.currentToken().type() != Token::Name) { reportError("Invalid vertex description"); delete[] attributes; @@ -516,30 +1167,29 @@ char* AsciiModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc, - uint32& vertexCount) + unsigned int& vertexCount) { - if (tok.nextToken() != Tokenizer::TokenName || - tok.getNameValue() != "vertices") + if (tok.nextToken() != VerticesToken) { reportError("Vertex data expected"); return NULL; } - if (tok.nextToken() != Tokenizer::TokenNumber) + if (tok.nextToken().type() != Token::Number) { reportError("Vertex count expected"); return NULL; } - double num = tok.getNumberValue(); + double num = tok.currentToken().numberValue(); if (num != floor(num) || num <= 0.0) { reportError("Bad vertex count for mesh"); return NULL; } - vertexCount = (uint32) num; - uint32 vertexDataSize = vertexDesc.stride * vertexCount; + vertexCount = (unsigned int) num; + unsigned int vertexDataSize = vertexDesc.stride * vertexCount; char* vertexData = new char[vertexDataSize]; if (vertexData == NULL) { @@ -547,15 +1197,15 @@ return NULL; } - uint32 offset = 0; + unsigned int offset = 0; double data[4]; - for (uint32 i = 0; i < vertexCount; i++, offset += vertexDesc.stride) + for (unsigned int i = 0; i < vertexCount; i++, offset += vertexDesc.stride) { assert(offset < vertexDataSize); - for (uint32 attr = 0; attr < vertexDesc.nAttributes; attr++) + for (unsigned int attr = 0; attr < vertexDesc.nAttributes; attr++) { Mesh::VertexAttributeFormat fmt = vertexDesc.attributes[attr].format; - /*uint32 nBytes = Mesh::getVertexAttributeSize(fmt); Unused*/ + /*unsigned int nBytes = Mesh::getVertexAttributeSize(fmt); Unused*/ int readCount = 0; switch (fmt) { @@ -580,19 +1230,19 @@ for (int j = 0; j < readCount; j++) { - if (tok.nextToken() != Tokenizer::TokenNumber) + if (!tok.nextToken().isNumber()) { reportError("Error in vertex data"); data[j] = 0.0; } else { - data[j] = tok.getNumberValue(); + data[j] = tok.currentToken().numberValue(); } // TODO: range check unsigned byte values } - uint32 base = offset + vertexDesc.attributes[attr].offset; + unsigned int base = offset + vertexDesc.attributes[attr].offset; if (fmt == Mesh::UByte4) { for (int k = 0; k < readCount; k++) @@ -616,8 +1266,7 @@ Mesh* AsciiModelLoader::loadMesh() { - if (tok.nextToken() != Tokenizer::TokenName || - tok.getNameValue() != "mesh") + if (tok.nextToken() != MeshToken) { reportError("Mesh definition expected"); return NULL; @@ -627,7 +1276,7 @@ if (vertexDesc == NULL) return NULL; - uint32 vertexCount = 0; + unsigned int vertexCount = 0; char* vertexData = loadVertices(*vertexDesc, vertexCount); if (vertexData == NULL) { @@ -640,41 +1289,44 @@ mesh->setVertices(vertexCount, vertexData); delete vertexDesc; - while (tok.nextToken() == Tokenizer::TokenName && - tok.getNameValue() != "end_mesh") + while (tok.nextToken().isName() && tok.currentToken() != EndMeshToken) { Mesh::PrimitiveGroupType type = - Mesh::parsePrimitiveGroupType(tok.getNameValue()); + Mesh::parsePrimitiveGroupType(tok.currentToken().stringValue()); if (type == Mesh::InvalidPrimitiveGroupType) { - reportError("Bad primitive group type: " + tok.getNameValue()); + reportError("Bad primitive group type: " + tok.currentToken().stringValue()); delete mesh; return NULL; } - if (tok.nextToken() != Tokenizer::TokenNumber) + if (!tok.nextToken().isInteger()) { reportError("Material index expected in primitive group"); delete mesh; return NULL; } - uint32 materialIndex; - if (tok.getNumberValue() == -1.0) + unsigned int materialIndex; + if (tok.currentToken().integerValue() == -1) + { materialIndex = ~0u; + } else - materialIndex = (uint32) tok.getNumberValue(); + { + materialIndex = (unsigned int) tok.currentToken().integerValue(); + } - if (tok.nextToken() != Tokenizer::TokenNumber) + if (!tok.nextToken().isInteger()) { reportError("Index count expected in primitive group"); delete mesh; return NULL; } - uint32 indexCount = (uint32) tok.getNumberValue(); + unsigned int indexCount = (unsigned int) tok.currentToken().integerValue(); - uint32* indices = new uint32[indexCount]; + Mesh::index32* indices = new Mesh::index32[indexCount]; if (indices == NULL) { reportError("Not enough memory to hold indices"); @@ -682,9 +1334,9 @@ return NULL; } - for (uint32 i = 0; i < indexCount; i++) + for (unsigned int i = 0; i < indexCount; i++) { - if (tok.nextToken() != Tokenizer::TokenNumber) + if (!tok.nextToken().isInteger()) { reportError("Incomplete index list in primitive group"); delete indices; @@ -692,7 +1344,7 @@ return NULL; } - uint32 index = (uint32) tok.getNumberValue(); + unsigned int index = (unsigned int) tok.currentToken().integerValue(); if (index >= vertexCount) { reportError("Index out of range"); @@ -724,17 +1376,11 @@ } // Parse material and mesh definitions - for (;;) + for (Token token = tok.nextToken(); token.type() != Token::End; token = tok.nextToken()) { - Tokenizer::TokenType ttype = tok.nextToken(); - - if (ttype == Tokenizer::TokenEnd) + if (token.isName()) { - break; - } - else if (ttype == Tokenizer::TokenName) - { - string name = tok.getNameValue(); + string name = tok.currentToken().stringValue(); tok.pushBack(); if (name == "material") @@ -746,7 +1392,7 @@ return NULL; } - Mesh::Material* material = loadMaterial(); + Material* material = loadMaterial(); if (material == NULL) { delete model; @@ -803,13 +1449,13 @@ { out << CEL_MODEL_HEADER_ASCII << "\n\n"; - for (uint32 matIndex = 0; model.getMaterial(matIndex); matIndex++) + for (unsigned int matIndex = 0; model.getMaterial(matIndex); matIndex++) { writeMaterial(*model.getMaterial(matIndex)); out << '\n'; } - for (uint32 meshIndex = 0; model.getMesh(meshIndex); meshIndex++) + for (unsigned int meshIndex = 0; model.getMesh(meshIndex); meshIndex++) { writeMesh(*model.getMesh(meshIndex)); out << '\n'; @@ -845,7 +1491,7 @@ out << ' ' << group.materialIndex << ' ' << group.nIndices << '\n'; // Print the indices, twelve per line - for (uint32 i = 0; i < group.nIndices; i++) + for (unsigned int i = 0; i < group.nIndices; i++) { out << group.indices[i]; if (i % 12 == 11 || i == group.nIndices - 1) @@ -873,7 +1519,7 @@ mesh.getVertexDescription()); out << '\n'; - for (uint32 groupIndex = 0; mesh.getGroup(groupIndex); groupIndex++) + for (unsigned int groupIndex = 0; mesh.getGroup(groupIndex); groupIndex++) { writeGroup(*mesh.getGroup(groupIndex)); out << '\n'; @@ -885,16 +1531,16 @@ void AsciiModelWriter::writeVertices(const void* vertexData, - uint32 nVertices, - uint32 stride, + unsigned int nVertices, + unsigned int stride, const Mesh::VertexDescription& desc) { const unsigned char* vertex = reinterpret_cast(vertexData); out << "vertices " << nVertices << '\n'; - for (uint32 i = 0; i < nVertices; i++, vertex += stride) + for (unsigned int i = 0; i < nVertices; i++, vertex += stride) { - for (uint32 attr = 0; attr < desc.nAttributes; attr++) + for (unsigned int attr = 0; attr < desc.nAttributes; attr++) { const unsigned char* ubdata = vertex + desc.attributes[attr].offset; const float* fdata = reinterpret_cast(ubdata); @@ -935,7 +1581,7 @@ AsciiModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc) { out << "vertexdesc\n"; - for (uint32 attr = 0; attr < desc.nAttributes; attr++) + for (unsigned int attr = 0; attr < desc.nAttributes; attr++) { // We should never have a vertex description with invalid // fields . . . @@ -1008,7 +1654,7 @@ void -AsciiModelWriter::writeMaterial(const Mesh::Material& material) +AsciiModelWriter::writeMaterial(const Material& material) { out << "material\n"; if (material.diffuse != DefaultDiffuse) @@ -1046,13 +1692,13 @@ out << "blend "; switch (material.blend) { - case Mesh::NormalBlend: + case Material::NormalBlend: out << "normal"; break; - case Mesh::AdditiveBlend: + case Material::AdditiveBlend: out << "add"; break; - case Mesh::PremultipliedAlphaBlend: + case Material::PremultipliedAlphaBlend: out << "premultiplied"; break; default: @@ -1062,50 +1708,38 @@ out << "\n"; } - for (int i = 0; i < Mesh::TextureSemanticMax; i++) + for (int i = 0; i < Material::TextureSemanticMax; i++) { - const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.maps[i]); - if (texInfo != NULL) + string texSource; + if (material.maps[i]) { - switch (Mesh::TextureSemantic(i)) + texSource = material.maps[i]->source(); + } + + if (!texSource.empty()) + { + switch (Material::TextureSemantic(i)) { - case Mesh::DiffuseMap: + case Material::DiffuseMap: out << "texture0"; break; - case Mesh::NormalMap: + case Material::NormalMap: out << "normalmap"; break; - case Mesh::SpecularMap: + case Material::SpecularMap: out << "specularmap"; break; - case Mesh::EmissiveMap: + case Material::EmissiveMap: out << "emissivemap"; break; default: assert(0); } - out << " \"" << texInfo->source << "\"\n"; + out << " \"" << texSource << "\"\n"; } } -#if 0 - if (material.maps[Mesh::DiffuseMap] != InvalidResource) - { - const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.tex0); - if (texInfo != NULL) - out << "texture0 \"" << texInfo->source << "\"\n"; - } - - if (material.tex1 != InvalidResource) - { - const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.tex1); - if (texInfo != NULL) - out << "texture1 \"" << texInfo->source << "\"\n"; - } -#endif - - out << "end_material\n"; } @@ -1181,7 +1815,7 @@ } -static bool readTypeColor(istream& in, Color& c) +static bool readTypeColor(istream& in, Material::Color& c) { if (readType(in) != CMOD_Color) return false; @@ -1189,7 +1823,7 @@ float r = readFloat(in); float g = readFloat(in); float b = readFloat(in); - c = Color(r, g, b); + c = Material::Color(r, g, b); return true; } @@ -1294,7 +1928,7 @@ return NULL; } - Mesh::Material* material = loadMaterial(); + Material* material = loadMaterial(); if (material == NULL) { delete model; @@ -1328,10 +1962,10 @@ } -Mesh::Material* +Material* BinaryModelLoader::loadMaterial() { - Mesh::Material* material = new Mesh::Material(); + Material* material = new Material(); material->diffuse = DefaultDiffuse; material->specular = DefaultSpecular; @@ -1392,20 +2026,20 @@ case CMOD_Blend: { int16 blendMode = readInt16(in); - if (blendMode < 0 || blendMode >= Mesh::BlendMax) + if (blendMode < 0 || blendMode >= Material::BlendMax) { reportError("Bad blend mode"); delete material; return NULL; } - material->blend = (Mesh::BlendMode) blendMode; + material->blend = (Material::BlendMode) blendMode; } break; case CMOD_Texture: { int16 texType = readInt16(in); - if (texType < 0 || texType >= Mesh::TextureSemanticMax) + if (texType < 0 || texType >= Material::TextureSemanticMax) { reportError("Bad texture type"); delete material; @@ -1427,7 +2061,15 @@ return NULL; } - ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(texfile, getTexturePath(), TextureInfo::WrapTexture)); + Material::TextureResource* tex = NULL; + if (getTextureLoader()) + { + tex = getTextureLoader()->loadTexture(texfile); + } + else + { + tex = new Material::DefaultTextureResource(texfile); + } material->maps[texType] = tex; } @@ -1459,7 +2101,7 @@ int maxAttributes = 16; int nAttributes = 0; - uint32 offset = 0; + unsigned int offset = 0; Mesh::VertexAttribute* attributes = new Mesh::VertexAttribute[maxAttributes]; for (;;) @@ -1527,7 +2169,7 @@ if (vertexDesc == NULL) return NULL; - uint32 vertexCount = 0; + unsigned int vertexCount = 0; char* vertexData = loadVertices(*vertexDesc, vertexCount); if (vertexData == NULL) { @@ -1557,8 +2199,8 @@ Mesh::PrimitiveGroupType type = static_cast(tok); - uint32 materialIndex = readUint(in); - uint32 indexCount = readUint(in); + unsigned int materialIndex = readUint(in); + unsigned int indexCount = readUint(in); uint32* indices = new uint32[indexCount]; if (indices == NULL) @@ -1568,7 +2210,7 @@ return NULL; } - for (uint32 i = 0; i < indexCount; i++) + for (unsigned int i = 0; i < indexCount; i++) { uint32 index = readUint(in); if (index >= vertexCount) @@ -1591,7 +2233,7 @@ char* BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc, - uint32& vertexCount) + unsigned int& vertexCount) { if (readToken(in) != CMOD_Vertices) { @@ -1600,7 +2242,7 @@ } vertexCount = readUint(in); - uint32 vertexDataSize = vertexDesc.stride * vertexCount; + unsigned int vertexDataSize = vertexDesc.stride * vertexCount; char* vertexData = new char[vertexDataSize]; if (vertexData == NULL) { @@ -1608,14 +2250,14 @@ return NULL; } - uint32 offset = 0; + unsigned int offset = 0; - for (uint32 i = 0; i < vertexCount; i++, offset += vertexDesc.stride) + for (unsigned int i = 0; i < vertexCount; i++, offset += vertexDesc.stride) { assert(offset < vertexDataSize); - for (uint32 attr = 0; attr < vertexDesc.nAttributes; attr++) + for (unsigned int attr = 0; attr < vertexDesc.nAttributes; attr++) { - uint32 base = offset + vertexDesc.attributes[attr].offset; + unsigned int base = offset + vertexDesc.attributes[attr].offset; Mesh::VertexAttributeFormat fmt = vertexDesc.attributes[attr].format; /*int readCount = 0; Unused*/ switch (fmt) @@ -1668,7 +2310,7 @@ // Utility functions for writing binary values to a file -static void writeUint(ostream& out, uint32 val) +static void writeUint32(ostream& out, uint32 val) { LE_TO_CPU_INT32(val, val); out.write(reinterpret_cast(&val), sizeof(uint32)); @@ -1704,7 +2346,7 @@ } -static void writeTypeColor(ostream& out, const Color& c) +static void writeTypeColor(ostream& out, const Material::Color& c) { writeType(out, CMOD_Color); writeFloat(out, c.red()); @@ -1726,10 +2368,10 @@ { out << CEL_MODEL_HEADER_BINARY; - for (uint32 matIndex = 0; model.getMaterial(matIndex); matIndex++) + for (unsigned int matIndex = 0; model.getMaterial(matIndex); matIndex++) writeMaterial(*model.getMaterial(matIndex)); - for (uint32 meshIndex = 0; model.getMesh(meshIndex); meshIndex++) + for (unsigned int meshIndex = 0; model.getMesh(meshIndex); meshIndex++) writeMesh(*model.getMesh(meshIndex)); return true; @@ -1740,12 +2382,13 @@ BinaryModelWriter::writeGroup(const Mesh::PrimitiveGroup& group) { writeInt16(out, static_cast(group.prim)); - writeUint(out, group.materialIndex); - writeUint(out, group.nIndices); + writeUint32(out, group.materialIndex); + writeUint32(out, group.nIndices); - // Print the indices, twelve per line - for (uint32 i = 0; i < group.nIndices; i++) - writeUint(out, group.indices[i]); + for (unsigned int i = 0; i < group.nIndices; i++) + { + writeUint32(out, group.indices[i]); + } } @@ -1761,7 +2404,7 @@ mesh.getVertexStride(), mesh.getVertexDescription()); - for (uint32 groupIndex = 0; mesh.getGroup(groupIndex); groupIndex++) + for (unsigned int groupIndex = 0; mesh.getGroup(groupIndex); groupIndex++) writeGroup(*mesh.getGroup(groupIndex)); writeToken(out, CMOD_EndMesh); @@ -1770,18 +2413,18 @@ void BinaryModelWriter::writeVertices(const void* vertexData, - uint32 nVertices, - uint32 stride, + unsigned int nVertices, + unsigned int stride, const Mesh::VertexDescription& desc) { const char* vertex = reinterpret_cast(vertexData); writeToken(out, CMOD_Vertices); - writeUint(out, nVertices); + writeUint32(out, nVertices); - for (uint32 i = 0; i < nVertices; i++, vertex += stride) + for (unsigned int i = 0; i < nVertices; i++, vertex += stride) { - for (uint32 attr = 0; attr < desc.nAttributes; attr++) + for (unsigned int attr = 0; attr < desc.nAttributes; attr++) { const char* cdata = vertex + desc.attributes[attr].offset; const float* fdata = reinterpret_cast(cdata); @@ -1823,7 +2466,7 @@ { writeToken(out, CMOD_VertexDesc); - for (uint32 attr = 0; attr < desc.nAttributes; attr++) + for (unsigned int attr = 0; attr < desc.nAttributes; attr++) { writeInt16(out, static_cast(desc.attributes[attr].semantic)); writeInt16(out, static_cast(desc.attributes[attr].format)); @@ -1834,7 +2477,7 @@ void -BinaryModelWriter::writeMaterial(const Mesh::Material& material) +BinaryModelWriter::writeMaterial(const Material& material) { writeToken(out, CMOD_Material); @@ -1874,30 +2517,35 @@ writeInt16(out, (int16) material.blend); } - for (int i = 0; i < Mesh::TextureSemanticMax; i++) + for (int i = 0; i < Material::TextureSemanticMax; i++) { - if (material.maps[i] != InvalidResource) + if (material.maps[i]) { - const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.maps[i]); - if (texInfo != NULL) + string texSource = material.maps[i]->source(); + if (!texSource.empty()) { writeToken(out, CMOD_Texture); writeInt16(out, (int16) i); - writeTypeString(out, texInfo->source); + writeTypeString(out, texSource); } } } -#if 0 - if (material.tex1 != InvalidResource) + + writeToken(out, CMOD_EndMaterial); +} + + +#ifdef CMOD_LOAD_TEST + +int main(int argc, char* argv[]) +{ + Model* model = LoadModel(cin); + if (model) { - const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.tex1); - if (texInfo != NULL) - { - writeToken(out, CMOD_Texture1); - writeTypeString(out, texInfo->source); - } + SaveModelAscii(model, cout); } -#endif - writeToken(out, CMOD_EndMaterial); + return 0; } + +#endif Index: src/celmodel/mesh.h =================================================================== --- src/celmodel/mesh.h (revision 0) +++ src/celmodel/mesh.h (working copy) @@ -1,31 +1,35 @@ // mesh.h // -// Copyright (C) 2004-2006, Chris Laurel +// Copyright (C) 2004-2010, Celestia Development Team +// Original version by Chris Laurel // // 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. -#ifndef _CELENGINE_MESH_H_ -#define _CELENGINE_MESH_H_ +#ifndef _CELMODEL_MESH_H_ +#define _CELMODEL_MESH_H_ -#include -#include -#include -#include -#include -#include -#include +#include "material.h" #include #include +#include +#include -class RenderContext; +namespace cmod +{ class Mesh { public: + // 32-bit index type + typedef unsigned int index32; + class BufferResource + { + }; + enum VertexAttributeSemantic { Position = 0, @@ -64,7 +68,7 @@ VertexAttribute(VertexAttributeSemantic _semantic, VertexAttributeFormat _format, - uint32 _offset) : + unsigned int _offset) : semantic(_semantic), format(_format), offset(_offset) @@ -73,13 +77,13 @@ VertexAttributeSemantic semantic; VertexAttributeFormat format; - uint32 offset; + unsigned int offset; }; struct VertexDescription { - VertexDescription(uint32 _stride, - uint32 _nAttributes, + VertexDescription(unsigned int _stride, + unsigned int _nAttributes, VertexAttribute* _attributes); VertexDescription(const VertexDescription& desc); ~VertexDescription(); @@ -93,8 +97,8 @@ VertexDescription& operator=(const VertexDescription&); - uint32 stride; - uint32 nAttributes; + unsigned int stride; + unsigned int nAttributes; VertexAttribute* attributes; private: @@ -105,39 +109,6 @@ VertexAttribute semanticMap[SemanticMax]; }; - enum TextureSemantic - { - DiffuseMap = 0, - NormalMap = 1, - SpecularMap = 2, - EmissiveMap = 3, - TextureSemanticMax = 4, - InvalidTextureSemantic = -1, - }; - - enum BlendMode - { - NormalBlend = 0, - AdditiveBlend = 1, - PremultipliedAlphaBlend = 2, - BlendMax = 3, - InvalidBlend = -1, - }; - - class Material - { - public: - Material(); - - Color diffuse; - Color emissive; - Color specular; - float specularPower; - float opacity; - BlendMode blend; - ResourceHandle maps[TextureSemanticMax]; - }; - enum PrimitiveGroupType { TriList = 0, @@ -157,32 +128,32 @@ PrimitiveGroup(); ~PrimitiveGroup(); - uint32 getPrimitiveCount() const; + unsigned int getPrimitiveCount() const; PrimitiveGroupType prim; - uint32 materialIndex; - uint32* indices; - uint32 nIndices; + unsigned int materialIndex; + index32* indices; + unsigned int nIndices; }; Mesh(); ~Mesh(); - void setVertices(uint32 _nVertices, void* vertexData); + void setVertices(unsigned int _nVertices, void* vertexData); bool setVertexDescription(const VertexDescription& desc); const VertexDescription& getVertexDescription() const; - const PrimitiveGroup* getGroup(uint32) const; - uint32 addGroup(PrimitiveGroup* group); - uint32 addGroup(PrimitiveGroupType prim, - uint32 materialIndex, - uint32 nIndices, - uint32* indices); - uint32 getGroupCount() const; - void remapIndices(const std::vector& indexMap); + const PrimitiveGroup* getGroup(unsigned int index) const; + unsigned int addGroup(PrimitiveGroup* group); + unsigned int addGroup(PrimitiveGroupType prim, + unsigned int materialIndex, + unsigned int nIndices, + index32* indices); + unsigned int getGroupCount() const; + void remapIndices(const std::vector& indexMap); void clearGroups(); - void remapMaterials(const std::vector& materialMap); + void remapMaterials(const std::vector& materialMap); /*! Reorder primitive groups so that groups with identical materials * appear sequentially in the primitive group list. This will reduce @@ -193,23 +164,21 @@ const std::string& getName() const; void setName(const std::string&); - bool pick(const Ray3d& r, double& distance) const; - void render(const std::vector& materials, - RenderContext&) const; + bool pick(const Eigen::Vector3d& origin, const Eigen::Vector3d& direction, double& distance) const; Eigen::AlignedBox getBoundingBox() const; void transform(const Eigen::Vector3f& translation, float scale); const void* getVertexData() const { return vertices; } - uint32 getVertexCount() const { return nVertices; } - uint32 getVertexStride() const { return vertexDesc.stride; } - uint32 getPrimitiveCount() const; + unsigned int getVertexCount() const { return nVertices; } + unsigned int getVertexStride() const { return vertexDesc.stride; } + unsigned int getPrimitiveCount() const; - static PrimitiveGroupType parsePrimitiveGroupType(const std::string&); - static VertexAttributeSemantic parseVertexAttributeSemantic(const std::string&); - static VertexAttributeFormat parseVertexAttributeFormat(const std::string&); - static TextureSemantic parseTextureSemantic(const std::string&); - static uint32 getVertexAttributeSize(VertexAttributeFormat); + static PrimitiveGroupType parsePrimitiveGroupType(const std::string&); + static VertexAttributeSemantic parseVertexAttributeSemantic(const std::string&); + static VertexAttributeFormat parseVertexAttributeFormat(const std::string&); + static Material::TextureSemantic parseTextureSemantic(const std::string&); + static unsigned int getVertexAttributeSize(VertexAttributeFormat); private: void recomputeBoundingBox(); @@ -217,15 +186,16 @@ private: VertexDescription vertexDesc; - uint32 nVertices; + unsigned int nVertices; void* vertices; - mutable GLuint vbObject; - mutable bool vbInitialized; + mutable BufferResource* vbResource; std::vector groups; std::string name; }; +} // namespace cmod + #endif // !_CELMESH_MESH_H_ Index: src/celmodel/model.h =================================================================== --- src/celmodel/model.h (revision 0) +++ src/celmodel/model.h (working copy) @@ -1,56 +1,22 @@ // model.h // -// Copyright (C) 2004-2006, Chris Laurel +// Copyright (C) 2004-2010, Celestia Development Team +// Original version by Chris Laurel // // 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. -#ifndef _CELENGINE_MODEL_H_ -#define _CELENGINE_MODEL_H_ +#ifndef _CELMODEL_MODEL_H_ +#define _CELMODEL_MODEL_H_ #include "mesh.h" -class Geometry + +namespace cmod { -public: - Geometry() {}; - virtual ~Geometry() {}; - //! Render the geometry in the specified OpenGL context - virtual void render(RenderContext& rc, double t = 0.0) = 0; - - /*! Find the closest intersection between the ray and the - * model. If the ray intersects the model, return true - * and set distance; otherwise return false and leave - * distance unmodified. - */ - virtual bool pick(const Ray3d& r, double& distance) const = 0; - - virtual bool isOpaque() const = 0; - - virtual bool isNormalized() const - { - return true; - } - - /*! Return true if the specified texture map type is used at - * all within this geometry object. This information is used - * to decide whether multiple rendering passes are required. - */ - virtual bool usesTextureType(Mesh::TextureSemantic) const - { - return false; - } - - /*! Load all textures used by the model. */ - virtual void loadTextures() - { - } -}; - - /*! * Model is the standard geometry object in Celestia. A Model * consists of a library of materials together with a list of @@ -60,7 +26,7 @@ * structure is exactly the one used in Celestia model (.cmod) * files. */ -class Model : public Geometry +class Model { public: Model(); @@ -69,60 +35,63 @@ /*! Return the material with the specified index, or NULL if * the index is out of range. */ - const Mesh::Material* getMaterial(uint32) const; + const Material* getMaterial(unsigned int index) const; /*! Add a new material to the model's material library; the * return value is the number of materials in the model. */ - uint32 addMaterial(const Mesh::Material*); + unsigned int addMaterial(const Material* material); /*! Return the number of materials in the model */ - uint32 getMaterialCount() const; + unsigned int getMaterialCount() const; /*! Return the total number of vertices in the model */ - uint32 getVertexCount() const; + unsigned int getVertexCount() const; /*! Return the total number of primitives in the model */ - uint32 getPrimitiveCount() const; + unsigned int getPrimitiveCount() const; /*! Return the mesh with the specified index, or NULL if the * index is out of range. */ - Mesh* getMesh(uint32) const; + Mesh* getMesh(unsigned int index) const; + /*! Return the total number of meshes withing the model. + */ + unsigned int getMeshCount() const; + /*! Add a new mesh to the model; the return value is the * total number of meshes in the model. */ - uint32 addMesh(Mesh*); + unsigned int addMesh(Mesh* mesh); - /*! Find the closest intersection between the ray and the - * model. If the ray intersects the model, return true - * and set distance; otherwise return false and leave - * distance unmodified. + /*! Find the closest intersection between the ray (given + * by origin and direction) and the model. If the ray + * intersects the model, return true and set distance; + * otherwise return false and leave distance unmodified. */ - virtual bool pick(const Ray3d& r, double& distance) const; + bool pick(const Eigen::Vector3d& rayOrigin, + const Eigen::Vector3d& rayDirection, + double& distance) const; - //! Render the model in the current OpenGL context - virtual void render(RenderContext&, double t = 0.0); - void transform(const Eigen::Vector3f& translation, float scale); - /*! Apply a uniform scale to the model so that it fits into + /** Apply a uniform scale to the model so that it fits into * a box with a center at centerOffset and a maximum side * length of one. */ void normalize(const Eigen::Vector3f& centerOffset); - /*! Return true if the specified texture map type is used at + /** Return true if the specified texture map type is used at * all within a mesh. This information is used to decide * if multiple rendering passes are required. */ - virtual bool usesTextureType(Mesh::TextureSemantic) const; + virtual bool usesTextureType(Material::TextureSemantic) const; - /*! Return true if the model has no translucent components. */ + /** Return true if the model has no translucent components. */ virtual bool isOpaque() const { return opaque; @@ -151,8 +120,6 @@ /*! Optimize the model by eliminating all duplicated materials */ void uniquifyMaterials(); - void loadTextures(); - /*! This comparator will roughly sort the model's meshes by * opacity so that transparent meshes are rendered last. It's far * from perfect, but covers a lot of cases. A better method of @@ -179,12 +146,14 @@ }; private: - std::vector materials; + std::vector materials; std::vector meshes; - bool textureUsage[Mesh::TextureSemanticMax]; + bool textureUsage[Material::TextureSemanticMax]; bool opaque; bool normalized; }; -#endif // !_CELENGINE_MODEL_H_ +} // namespace + +#endif // !_CELMODEL_MODEL_H_ Index: src/celmodel/modelfile.h =================================================================== --- src/celmodel/modelfile.h (revision 0) +++ src/celmodel/modelfile.h (working copy) @@ -1,14 +1,15 @@ // modelfile.h // -// Copyright (C) 2004, Chris Laurel +// Copyright (C) 2004-2010, Celestia Development Team +// Original version by Chris Laurel // // 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. -#ifndef _CELMESH_MODELFILE_H_ -#define _CELMESH_MODELFILE_H_ +#ifndef _CELMODEL_MODELFILE_H_ +#define _CELMODEL_MODELFILE_H_ #include "model.h" #include @@ -18,6 +19,22 @@ #define CEL_MODEL_HEADER_ASCII "#celmodel__ascii" #define CEL_MODEL_HEADER_BINARY "#celmodel_binary" + +namespace cmod +{ + +/** Texture loading interface. Applications which want custom behavor for + * texture loading should pass an instance of a TextureLoader subclass to + * one of the model loading functions. + */ +class TextureLoader +{ +public: + virtual ~TextureLoader() {}; + virtual Material::TextureResource* loadTexture(const std::string& name) = 0; +}; + + class ModelLoader { public: @@ -27,9 +44,9 @@ virtual Model* load() = 0; const std::string& getErrorMessage() const; - void setTexturePath(const std::string&); - const std::string& getTexturePath() const; - + TextureLoader* getTextureLoader() const; + void setTextureLoader(TextureLoader* _textureLoader); + static ModelLoader* OpenModel(std::istream& in); protected: @@ -37,7 +54,7 @@ private: std::string errorMessage; - std::string texPath; + TextureLoader* textureLoader; }; @@ -51,8 +68,7 @@ -Model* LoadModel(std::istream&); -Model* LoadModel(std::istream& in, const std::string& texPath); +Model* LoadModel(std::istream& in, TextureLoader* textureLoader = NULL); bool SaveModelAscii(const Model* model, std::ostream& out); bool SaveModelBinary(const Model* model, std::ostream& out); @@ -88,4 +104,6 @@ CMOD_Color = 7, }; -#endif // !_CELMESH_MODELFILE_H_ +} + +#endif // !_CELMODEL_MODELFILE_H_ Index: src/celmodel/mesh.cpp =================================================================== --- src/celmodel/mesh.cpp (revision 0) +++ src/celmodel/mesh.cpp (working copy) @@ -1,6 +1,6 @@ // mesh.cpp // -// Copyright (C) 2004-2009, the Celestia Development Team +// Copyright (C) 2004-2010, the Celestia Development Team // Original version by Chris Laurel // // This program is free software; you can redistribute it and/or @@ -9,14 +9,13 @@ // of the License, or (at your option) any later version. #include "mesh.h" -#include "rendcontext.h" #include #include #include #include #include -#include +using namespace cmod; using namespace Eigen; using namespace std; @@ -31,41 +30,8 @@ }; -// 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; -} - - -Mesh::Material::Material() : - diffuse(0.0f, 0.0f, 0.0f), - emissive(0.0f, 0.0f, 0.0f), - specular(0.0f, 0.0f, 0.0f), - specularPower(1.0f), - opacity(1.0f), - blend(NormalBlend) -{ - for (int i = 0; i < TextureSemanticMax; i++) - maps[i] = InvalidResource; - -} - - -Mesh::VertexDescription::VertexDescription(uint32 _stride, - uint32 _nAttributes, +Mesh::VertexDescription::VertexDescription(unsigned int _stride, + unsigned int _nAttributes, VertexAttribute* _attributes) : stride(_stride), nAttributes(_nAttributes), @@ -74,7 +40,7 @@ if (nAttributes != 0) { attributes = new VertexAttribute[nAttributes]; - for (uint32 i = 0; i < nAttributes; i++) + for (unsigned int i = 0; i < nAttributes; i++) attributes[i] = _attributes[i]; buildSemanticMap(); } @@ -89,7 +55,7 @@ if (nAttributes != 0) { attributes = new VertexAttribute[nAttributes]; - for (uint32 i = 0; i < nAttributes; i++) + for (unsigned int i = 0; i < nAttributes; i++) attributes[i] = desc.attributes[i]; buildSemanticMap(); } @@ -108,7 +74,7 @@ nAttributes = desc.nAttributes; stride = desc.stride; - for (uint32 i = 0; i < nAttributes; i++) + for (unsigned int i = 0; i < nAttributes; i++) attributes[i] = desc.attributes[i]; clearSemanticMap(); buildSemanticMap(); @@ -122,7 +88,7 @@ bool Mesh::VertexDescription::validate() const { - for (uint32 i = 0; i < nAttributes; i++) + for (unsigned int i = 0; i < nAttributes; i++) { VertexAttribute& attr = attributes[i]; @@ -151,7 +117,7 @@ void Mesh::VertexDescription::buildSemanticMap() { - for (uint32 i = 0; i < nAttributes; i++) + for (unsigned int i = 0; i < nAttributes; i++) semanticMap[attributes[i].semantic] = attributes[i]; } @@ -159,7 +125,7 @@ void Mesh::VertexDescription::clearSemanticMap() { - for (uint32 i = 0; i < SemanticMax; i++) + for (unsigned int i = 0; i < SemanticMax; i++) semanticMap[i] = VertexAttribute(); } @@ -176,7 +142,7 @@ } -uint32 +unsigned int Mesh::PrimitiveGroup::getPrimitiveCount() const { switch (prim) @@ -204,8 +170,7 @@ vertexDesc(0, 0, NULL), nVertices(0), vertices(NULL), - vbObject(0), - vbInitialized(false) + vbResource(0) { } @@ -223,15 +188,15 @@ if (vertices != NULL) delete[] static_cast(vertices); - if (vbObject != 0) + if (vbResource) { - glDeleteBuffersARB(1, &vbObject); + delete vbResource; } } void -Mesh::setVertices(uint32 _nVertices, void* vertexData) +Mesh::setVertices(unsigned int _nVertices, void* vertexData) { nVertices = _nVertices; vertices = vertexData; @@ -257,7 +222,7 @@ const Mesh::PrimitiveGroup* -Mesh::getGroup(uint32 index) const +Mesh::getGroup(unsigned int index) const { if (index >= groups.size()) return NULL; @@ -266,7 +231,7 @@ } -uint32 +unsigned int Mesh::addGroup(PrimitiveGroup* group) { groups.push_back(group); @@ -274,11 +239,11 @@ } -uint32 +unsigned int Mesh::addGroup(PrimitiveGroupType prim, - uint32 materialIndex, - uint32 nIndices, - uint32* indices) + unsigned int materialIndex, + unsigned int nIndices, + index32* indices) { PrimitiveGroup* g = new PrimitiveGroup(); g->prim = prim; @@ -290,7 +255,7 @@ } -uint32 +unsigned int Mesh::getGroupCount() const { return groups.size(); @@ -325,13 +290,13 @@ void -Mesh::remapIndices(const vector& indexMap) +Mesh::remapIndices(const vector& indexMap) { for (vector::iterator iter = groups.begin(); iter != groups.end(); iter++) { PrimitiveGroup* group = *iter; - for (uint32 i = 0; i < group->nIndices; i++) + for (index32 i = 0; i < group->nIndices; i++) { group->indices[i] = indexMap[group->indices[i]]; } @@ -340,7 +305,7 @@ void -Mesh::remapMaterials(const vector& materialMap) +Mesh::remapMaterials(const vector& materialMap) { for (vector::iterator iter = groups.begin(); iter != groups.end(); iter++) @@ -371,7 +336,7 @@ bool -Mesh::pick(const Ray3d& ray, double& distance) const +Mesh::pick(const Vector3d& rayOrigin, const Vector3d& rayDirection, double& distance) const { double maxDistance = 1.0e30; double closest = maxDistance; @@ -384,7 +349,7 @@ return false; } - uint posOffset = vertexDesc.getAttribute(Position).offset; + unsigned int posOffset = vertexDesc.getAttribute(Position).offset; char* vdata = reinterpret_cast(vertices); // Iterate over all primitive groups in the mesh @@ -392,7 +357,7 @@ iter != groups.end(); iter++) { Mesh::PrimitiveGroupType primType = (*iter)->prim; - uint32 nIndices = (*iter)->nIndices; + index32 nIndices = (*iter)->nIndices; // Only attempt to compute the intersection of the ray with triangle // groups. @@ -400,10 +365,10 @@ (nIndices >= 3) && !(primType == TriList && nIndices % 3 != 0)) { - uint32 index = 0; - uint32 i0 = (*iter)->indices[0]; - uint32 i1 = (*iter)->indices[1]; - uint32 i2 = (*iter)->indices[2]; + index32 index = 0; + index32 i0 = (*iter)->indices[0]; + index32 i1 = (*iter)->indices[1]; + index32 i2 = (*iter)->indices[2]; // Iterate over the triangles in the primitive group do @@ -419,14 +384,14 @@ Vector3d n = e0.cross(e1); // c is the cosine of the angle between the ray and triangle normal - double c = n.dot(ray.direction); + double c = n.dot(rayDirection); // If the ray is parallel to the triangle, it either misses the // triangle completely, or is contained in the triangle's plane. // If it's contained in the plane, we'll still call it a miss. if (c != 0.0) { - double t = (n.dot(v0 - ray.origin)) / c; + double t = (n.dot(v0 - rayOrigin)) / c; if (t < closest && t > 0.0) { double m00 = e0.dot(e0); @@ -436,7 +401,7 @@ double det = m00 * m11 - m01 * m10; if (det != 0.0) { - Vector3d p = ray.point(t); + Vector3d p = rayOrigin + rayDirection * t; Vector3d q = p - v0; double q0 = e0.dot(q); double q1 = e1.dot(q); @@ -498,6 +463,7 @@ } +#if 0 void Mesh::render(const std::vector& materials, RenderContext& rc) const @@ -537,7 +503,7 @@ rc.setVertexArrays(vertexDesc, vertices); } - uint32 lastMaterial = ~0u; + unsigned int lastMaterial = ~0u; // Iterate over all primitive groups in the mesh for (vector::const_iterator iter = groups.begin(); @@ -545,7 +511,7 @@ { // Set up the material const Material* mat = NULL; - uint32 materialIndex = (*iter)->materialIndex; + unsigned int materialIndex = (*iter)->materialIndex; if (materialIndex != lastMaterial && materialIndex < materials.size()) mat = materials[materialIndex]; @@ -556,6 +522,7 @@ if (vbObject != 0) glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } +#endif AlignedBox @@ -576,7 +543,7 @@ int pointSizeOffset = (int) vertexDesc.getAttribute(PointSize).offset - (int) vertexDesc.getAttribute(Position).offset; - for (uint32 i = 0; i < nVertices; i++, vdata += vertexDesc.stride) + for (unsigned int i = 0; i < nVertices; i++, vdata += vertexDesc.stride) { Vector3f center = Map(reinterpret_cast(vdata)); float pointSize = (reinterpret_cast(vdata + pointSizeOffset))[0]; @@ -588,7 +555,7 @@ } else { - for (uint32 i = 0; i < nVertices; i++, vdata += vertexDesc.stride) + for (unsigned int i = 0; i < nVertices; i++, vdata += vertexDesc.stride) bbox.extend(Map(reinterpret_cast(vdata))); } @@ -603,7 +570,7 @@ return; char* vdata = reinterpret_cast(vertices) + vertexDesc.getAttribute(Position).offset; - uint32 i; + unsigned int i; // Scale and translate the vertex positions for (i = 0; i < nVertices; i++, vdata += vertexDesc.stride) @@ -627,10 +594,10 @@ } -uint32 +unsigned int Mesh::getPrimitiveCount() const { - uint32 count = 0; + unsigned int count = 0; for (vector::const_iterator iter = groups.begin(); iter != groups.end(); iter++) @@ -642,6 +609,7 @@ } + Mesh::PrimitiveGroupType Mesh::parsePrimitiveGroupType(const string& name) { @@ -710,23 +678,23 @@ } -Mesh::TextureSemantic +Material::TextureSemantic Mesh::parseTextureSemantic(const string& name) { if (name == "texture0") - return DiffuseMap; + return Material::DiffuseMap; else if (name == "normalmap") - return NormalMap; + return Material::NormalMap; else if (name == "specularmap") - return SpecularMap; + return Material::SpecularMap; else if (name == "emissivemap") - return EmissiveMap; + return Material::EmissiveMap; else - return InvalidTextureSemantic; + return Material::InvalidTextureSemantic; } -uint32 +unsigned int Mesh::getVertexAttributeSize(VertexAttributeFormat fmt) { switch (fmt) Index: src/celutil/util.h =================================================================== --- src/celutil/util.h (revision 4952) +++ src/celutil/util.h (working copy) @@ -16,9 +16,10 @@ #include #include -// A little trickery to get something like a compile time assert in C++ +#ifndef COMPILE_TYPE_ASSERT #define COMPILE_TIME_ASSERT(pred) \ switch(0){case 0: case pred:;} +#endif // gettext / libintl setup #define _(string) gettext (string) Index: src/celutil/bytes.h =================================================================== --- src/celutil/bytes.h (revision 4952) +++ src/celutil/bytes.h (working copy) @@ -7,8 +7,8 @@ // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -#ifndef _BYTES_H_ -#define _BYTES_H_ +#ifndef _CELUTIL_BYTES_H_ +#define _CELUTIL_BYTES_H_ #ifndef _WIN32 #ifndef TARGET_OS_MAC @@ -16,7 +16,10 @@ #endif /* TARGET_OS_MAC */ #endif /* _WIN32 */ -#include +#ifndef COMPILE_TYPE_ASSERT +#define COMPILE_TIME_ASSERT(pred) \ + switch(0){case 0: case pred:;} +#endif /* Use the system byteswap.h definitions if we have them */ #ifdef HAVE_BYTESWAP_H @@ -94,4 +97,4 @@ #endif -#endif // _BYTES_H_ +#endif // _CELUTIL_BYTES_H_