2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #if !defined( INCLUDED_MODEL_H )
23 #define INCLUDED_MODEL_H
25 #include "globaldefs.h"
27 #include "renderable.h"
28 #include "selectable.h"
29 #include "modelskin.h"
31 #include "math/frustum.h"
32 #include "string/string.h"
33 #include "generic/static.h"
34 #include "stream/stringstream.h"
37 #include "instancelib.h"
38 #include "transformlib.h"
39 #include "traverselib.h"
42 class VectorLightList : public LightList {
43 typedef std::vector<const RendererLight *> Lights;
46 void addLight(const RendererLight &light)
48 m_lights.push_back(&light);
56 void evaluateLights() const
60 void lightsChanged() const
64 void forEachLight(const RendererLightCallback &callback) const
66 for (Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i) {
72 inline VertexPointer vertexpointer_arbitrarymeshvertex(const ArbitraryMeshVertex *array)
74 return VertexPointer(VertexPointer::pointer(&array->vertex), sizeof(ArbitraryMeshVertex));
77 inline void parseTextureName(CopiedString &name, const char *token)
79 StringOutputStream cleaned(256);
80 cleaned << PathCleaned(token);
81 name = StringRange(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
84 // generic renderable triangle surface
86 public OpenGLRenderable {
88 typedef VertexBuffer<ArbitraryMeshVertex> vertices_t;
89 typedef IndexBuffer indices_t;
93 CopiedString m_shader;
96 vertices_t m_vertices;
101 m_state = GlobalShaderCache().capture(m_shader.c_str());
106 GlobalShaderCache().release(m_shader.c_str());
112 : m_shader(""), m_state(0)
122 vertices_t &vertices()
132 void setShader(const char *name)
135 parseTextureName(m_shader, name);
139 const char *getShader() const
141 return m_shader.c_str();
144 Shader *getState() const
151 m_aabb_local = AABB();
152 for (vertices_t::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i) {
153 aabb_extend_by_point_safe(m_aabb_local, reinterpret_cast<const Vector3 &>((*i).vertex ));
157 for (Surface::indices_t::iterator i = m_indices.begin(); i != m_indices.end(); i += 3) {
158 ArbitraryMeshVertex &a = m_vertices[*(i + 0)];
159 ArbitraryMeshVertex &b = m_vertices[*(i + 1)];
160 ArbitraryMeshVertex &c = m_vertices[*(i + 2)];
162 ArbitraryMeshTriangle_sumTangents(a, b, c);
165 for (Surface::vertices_t::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i) {
166 vector3_normalise(reinterpret_cast<Vector3 &>((*i).tangent ));
167 vector3_normalise(reinterpret_cast<Vector3 &>((*i).bitangent ));
171 void render(RenderStateFlags state) const
174 if ((state & RENDER_BUMP) != 0) {
175 if (GlobalShaderCache().useShaderLanguage()) {
176 glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
177 glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
178 &m_vertices.data()->texcoord);
179 glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
180 &m_vertices.data()->tangent);
181 glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
182 &m_vertices.data()->bitangent);
184 glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
185 glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
186 glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->tangent);
187 glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
188 &m_vertices.data()->bitangent);
191 glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
192 glTexCoordPointer(2, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
194 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->vertex);
195 glDrawElements(GL_TRIANGLES, GLsizei(m_indices.size()), RenderIndexTypeID, m_indices.data());
197 glBegin( GL_TRIANGLES );
198 for ( unsigned int i = 0; i < m_indices.size(); ++i )
200 glTexCoord2fv( &m_vertices[m_indices[i]].texcoord.s );
201 glNormal3fv( &m_vertices[m_indices[i]].normal.x );
202 glVertex3fv( &m_vertices[m_indices[i]].vertex.x );
210 for (VertexBuffer<ArbitraryMeshVertex>::const_iterator i = m_vertices.begin(); i != m_vertices.end(); ++i) {
211 Vector3 normal = vector3_added(vertex3f_to_vector3((*i).vertex),
212 vector3_scaled(normal3f_to_vector3((*i).normal), 8));
213 glVertex3fv(vertex3f_to_array((*i).vertex));
214 glVertex3fv(vector3_to_array(normal));
220 VolumeIntersectionValue intersectVolume(const VolumeTest &test, const Matrix4 &localToWorld) const
222 return test.TestAABB(m_aabb_local, localToWorld);
225 const AABB &localAABB() const
230 void render(Renderer &renderer, const Matrix4 &localToWorld, Shader *state) const
232 renderer.SetState(state, Renderer::eFullMaterials);
233 renderer.addRenderable(*this, localToWorld);
236 void render(Renderer &renderer, const Matrix4 &localToWorld) const
238 render(renderer, localToWorld, m_state);
241 void testSelect(Selector &selector, SelectionTest &test, const Matrix4 &localToWorld)
243 test.BeginMesh(localToWorld);
245 SelectionIntersection best;
247 vertexpointer_arbitrarymeshvertex(m_vertices.data()),
248 IndexPointer(m_indices.data(), IndexPointer::index_type(m_indices.size())),
252 selector.addIntersection(best);
257 // generic model node
261 typedef std::vector<Surface *> surfaces_t;
262 surfaces_t m_surfaces;
266 Callback<void()> m_lightsChanged;
270 for (surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i) {
275 typedef surfaces_t::const_iterator const_iterator;
277 const_iterator begin() const
279 return m_surfaces.begin();
282 const_iterator end() const
284 return m_surfaces.end();
287 std::size_t size() const
289 return m_surfaces.size();
292 Surface &newSurface()
294 m_surfaces.push_back(new Surface);
295 return *m_surfaces.back();
300 m_aabb_local = AABB();
301 for (surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i) {
302 aabb_extend_by_aabb_safe(m_aabb_local, (*i)->localAABB());
306 VolumeIntersectionValue intersectVolume(const VolumeTest &test, const Matrix4 &localToWorld) const
308 return test.TestAABB(m_aabb_local, localToWorld);
311 virtual const AABB &localAABB() const
316 void testSelect(Selector &selector, SelectionTest &test, const Matrix4 &localToWorld)
318 for (surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i) {
319 if ((*i)->intersectVolume(test.getVolume(), localToWorld) != c_volumeOutside) {
320 (*i)->testSelect(selector, test, localToWorld);
326 inline void Surface_addLight(const Surface &surface, VectorLightList &lights, const Matrix4 &localToWorld,
327 const RendererLight &light)
329 if (light.testAABB(aabb_for_oriented_aabb(surface.localAABB(), localToWorld))) {
330 lights.addLight(light);
334 class ModelInstance :
335 public scene::Instance,
337 public SelectionTestable,
338 public LightCullable,
339 public SkinnedModel {
341 InstanceTypeCastTable m_casts;
345 InstanceContainedCast<ModelInstance, Bounded>::install(m_casts);
346 InstanceContainedCast<ModelInstance, Cullable>::install(m_casts);
347 InstanceStaticCast<ModelInstance, Renderable>::install(m_casts);
348 InstanceStaticCast<ModelInstance, SelectionTestable>::install(m_casts);
349 InstanceStaticCast<ModelInstance, SkinnedModel>::install(m_casts);
352 InstanceTypeCastTable &get()
360 const LightList *m_lightList;
361 typedef Array<VectorLightList> SurfaceLightLists;
362 SurfaceLightLists m_surfaceLightLists;
374 typedef Array<Remap> SurfaceRemaps;
375 SurfaceRemaps m_skins;
378 typedef LazyStatic<TypeCasts> StaticTypeCasts;
380 Bounded &get(NullType<Bounded>)
385 Cullable &get(NullType<Cullable>)
392 m_lightList->lightsChanged();
395 typedef MemberCaller<ModelInstance, void(), &ModelInstance::lightsChanged> LightsChangedCaller;
397 void constructRemaps()
399 ModelSkin *skin = NodeTypeCast<ModelSkin>::cast(path().parent());
400 if (skin != 0 && skin->realised()) {
401 SurfaceRemaps::iterator j = m_skins.begin();
402 for (Model::const_iterator i = m_model.begin(); i != m_model.end(); ++i, ++j) {
403 const char *remap = skin->getRemap((*i)->getShader());
404 if (!string_empty(remap)) {
406 (*j).second = GlobalShaderCache().capture(remap);
417 for (SurfaceRemaps::iterator i = m_skins.begin(); i != m_skins.end(); ++i) {
418 if ((*i).second != 0) {
419 GlobalShaderCache().release((*i).first.c_str());
427 ASSERT_MESSAGE(m_skins.size() == m_model.size(), "ERROR");
432 ModelInstance(const scene::Path &path, scene::Instance *parent, Model &model) :
433 Instance(path, parent, this, StaticTypeCasts::instance().get()),
435 m_surfaceLightLists(m_model.size()),
436 m_skins(m_model.size())
438 m_lightList = &GlobalShaderCache().attach(*this);
439 m_model.m_lightsChanged = LightsChangedCaller(*this);
441 Instance::setTransformChangedCallback(LightsChangedCaller(*this));
450 Instance::setTransformChangedCallback(Callback<void()>());
452 m_model.m_lightsChanged = Callback<void()>();
453 GlobalShaderCache().detach(*this);
456 void render(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
458 SurfaceLightLists::const_iterator j = m_surfaceLightLists.begin();
459 SurfaceRemaps::const_iterator k = m_skins.begin();
460 for (Model::const_iterator i = m_model.begin(); i != m_model.end(); ++i, ++j, ++k) {
461 if ((*i)->intersectVolume(volume, localToWorld) != c_volumeOutside) {
462 renderer.setLights(*j);
463 (*i)->render(renderer, localToWorld, (*k).second != 0 ? (*k).second : (*i)->getState());
468 void renderSolid(Renderer &renderer, const VolumeTest &volume) const
470 m_lightList->evaluateLights();
472 render(renderer, volume, Instance::localToWorld());
475 void renderWireframe(Renderer &renderer, const VolumeTest &volume) const
477 renderSolid(renderer, volume);
480 void testSelect(Selector &selector, SelectionTest &test)
482 m_model.testSelect(selector, test, Instance::localToWorld());
485 bool testLight(const RendererLight &light) const
487 return light.testAABB(worldAABB());
490 void insertLight(const RendererLight &light)
492 const Matrix4 &localToWorld = Instance::localToWorld();
493 SurfaceLightLists::iterator j = m_surfaceLightLists.begin();
494 for (Model::const_iterator i = m_model.begin(); i != m_model.end(); ++i) {
495 Surface_addLight(*(*i), *j++, localToWorld, light);
501 for (SurfaceLightLists::iterator i = m_surfaceLightLists.begin(); i != m_surfaceLightLists.end(); ++i) {
507 class ModelNode : public scene::Node::Symbiot, public scene::Instantiable {
509 NodeTypeCastTable m_casts;
513 NodeStaticCast<ModelNode, scene::Instantiable>::install(m_casts);
516 NodeTypeCastTable &get()
524 InstanceSet m_instances;
528 typedef LazyStatic<TypeCasts> StaticTypeCasts;
530 ModelNode() : m_node(this, this, StaticTypeCasts::instance().get())
549 scene::Instance *create(const scene::Path &path, scene::Instance *parent)
551 return new ModelInstance(path, parent, m_model);
554 void forEachInstance(const scene::Instantiable::Visitor &visitor)
556 m_instances.forEachInstance(visitor);
559 void insert(scene::Instantiable::Observer *observer, const scene::Path &path, scene::Instance *instance)
561 m_instances.insert(observer, path, instance);
564 scene::Instance *erase(scene::Instantiable::Observer *observer, const scene::Path &path)
566 return m_instances.erase(observer, path);
572 Surface_constructQuad(Surface &surface, const Vector3 &a, const Vector3 &b, const Vector3 &c, const Vector3 &d,
573 const Vector3 &normal)
575 surface.vertices().push_back(
577 vertex3f_for_vector3(a),
578 normal3f_for_vector3(normal),
579 texcoord2f_from_array(aabb_texcoord_topleft)
582 surface.vertices().push_back(
584 vertex3f_for_vector3(b),
585 normal3f_for_vector3(normal),
586 texcoord2f_from_array(aabb_texcoord_topright)
589 surface.vertices().push_back(
591 vertex3f_for_vector3(c),
592 normal3f_for_vector3(normal),
593 texcoord2f_from_array(aabb_texcoord_botright)
596 surface.vertices().push_back(
598 vertex3f_for_vector3(d),
599 normal3f_for_vector3(normal),
600 texcoord2f_from_array(aabb_texcoord_botleft)
605 inline void Model_constructNull(Model &model)
607 Surface &surface = model.newSurface();
609 AABB aabb(Vector3(0, 0, 0), Vector3(8, 8, 8));
612 aabb_corners(aabb, points);
614 surface.vertices().reserve(24);
616 Surface_constructQuad(surface, points[2], points[1], points[5], points[6], aabb_normals[0]);
617 Surface_constructQuad(surface, points[1], points[0], points[4], points[5], aabb_normals[1]);
618 Surface_constructQuad(surface, points[0], points[1], points[2], points[3], aabb_normals[2]);
619 Surface_constructQuad(surface, points[0], points[3], points[7], points[4], aabb_normals[3]);
620 Surface_constructQuad(surface, points[3], points[2], points[6], points[7], aabb_normals[4]);
621 Surface_constructQuad(surface, points[7], points[6], points[5], points[4], aabb_normals[5]);
623 surface.indices().reserve(36);
625 RenderIndex indices[36] = {
629 12, 13, 14, 12, 14, 15,
630 16, 17, 18, 16, 18, 19,
631 20, 21, 22, 10, 22, 23,
634 for (RenderIndex *i = indices; i != indices + (sizeof(indices) / sizeof(RenderIndex)); ++i) {
635 surface.indices().insert(*i);
638 surface.setShader("");
640 surface.updateAABB();