1 // vertexlist.cpp
2 //
3 // Copyright (C) 2001, Chris Laurel
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 
10 #include <algorithm>
11 #include "gl.h"
12 #include "glext.h"
13 #include "vecgl.h"
14 #include "vertexlist.h"
15 
16 using namespace std;
17 
18 
VertexList(uint32 _parts,uint32 initialVertexPoolSize)19 VertexList::VertexList(uint32 _parts, uint32 initialVertexPoolSize) :
20     parts(_parts),
21     nVertices(0),
22     maxVertices(0),
23     vertices(NULL),
24     diffuseColor(1.0f, 1.0f, 1.0f),
25     specularColor(0.0f, 0.0f, 0.0f),
26     shininess(0.0f),
27     texture(InvalidResource),
28     bbox()
29 {
30     if (initialVertexPoolSize > 0)
31     {
32         maxVertices = initialVertexPoolSize;
33         vertices = new VertexPart[vertexSize * maxVertices];
34     }
35 
36     vertexSize = 3;
37     if ((parts & VertexNormal) != 0)
38         vertexSize += 3;
39     if ((parts & VertexColor0) != 0)
40         vertexSize += 1;
41     if ((parts & TexCoord0) != 0)
42         vertexSize += 2;
43     if ((parts & TexCoord1) != 0)
44         vertexSize += 2;
45 }
46 
47 
~VertexList()48 VertexList::~VertexList()
49 {
50     // HACK: Don't delete the vertex data; the VertexList class as an intermediate
51     // step in converting from 3DS models to Celestia models, and after the
52     // conversion, the Celestia model will own the vertex data pointer.
53 #if 0
54     if (vertices != NULL)
55         delete[] vertices;
56 #endif
57 }
58 
59 
render()60 void VertexList::render()
61 {
62     GLsizei stride = sizeof(VertexPart) * vertexSize;
63     uint32 start = 3;
64 
65     // Vertex points
66     glEnableClientState(GL_VERTEX_ARRAY);
67     glVertexPointer(3, GL_FLOAT, stride, static_cast<void*>(vertices));
68 
69     // Vertex normals
70     if ((parts & VertexNormal) != 0)
71     {
72         glEnableClientState(GL_NORMAL_ARRAY);
73         glNormalPointer(GL_FLOAT, stride, static_cast<void*>(&vertices[start]));
74         start += 3;
75     }
76     else
77     {
78         glDisableClientState(GL_NORMAL_ARRAY);
79     }
80 
81     // Vertex color
82     if ((parts & VertexColor0) != 0)
83     {
84         glEnableClientState(GL_COLOR_ARRAY);
85         glColorPointer(4, GL_UNSIGNED_BYTE, stride,
86                        static_cast<void*>(&vertices[start]));
87         start += 1;
88     }
89     else
90     {
91         glDisableClientState(GL_COLOR_ARRAY);
92         glColor(diffuseColor);
93     }
94 
95     // Texture coordinates
96     if ((parts & TexCoord0) != 0)
97     {
98         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
99         glTexCoordPointer(2, GL_FLOAT, stride,
100                           static_cast<void*>(&vertices[start]));
101         start += 2;
102     }
103     else
104     {
105         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
106     }
107 
108     if ((parts & TexCoord1) != 0)
109     {
110         // glEnableClientState(GL_TEXTURE_COORD_ARRAY);
111         glTexCoordPointer(2, GL_FLOAT, stride,
112                           static_cast<void*>(&vertices[start]));
113         start += 2;
114     }
115 
116     glDrawArrays(GL_TRIANGLES, 0, nVertices);
117 }
118 
119 
addVertex(const Vertex & v)120 void VertexList::addVertex(const Vertex& v)
121 {
122     if (nVertices == maxVertices)
123     {
124         if (maxVertices == 0)
125         {
126             vertices = new VertexPart[16 * vertexSize];
127             maxVertices = 16;
128         }
129         else
130         {
131             VertexPart* newVertices = new VertexPart[maxVertices * 2 * vertexSize];
132             copy(vertices, vertices + nVertices * vertexSize, newVertices);
133             delete[] vertices;
134             vertices = newVertices;
135             maxVertices *= 2;
136         }
137     }
138 
139     uint32 n = nVertices * vertexSize;
140     vertices[n++].f = v.point.x;
141     vertices[n++].f = v.point.y;
142     vertices[n++].f = v.point.z;
143     if ((parts & VertexNormal) != 0)
144     {
145         vertices[n++].f = v.normal.x;
146         vertices[n++].f = v.normal.y;
147         vertices[n++].f = v.normal.z;
148     }
149     if ((parts & VertexColor0) != 0)
150     {
151         vertices[n].c[0] = (int) (v.color.red() * 255.99f);
152         vertices[n].c[1] = (int) (v.color.green() * 255.99f);
153         vertices[n].c[2] = (int) (v.color.blue() * 255.99f);
154         vertices[n].c[3] = (int) (v.color.alpha() * 255.99f);
155         n++;
156     }
157     if ((parts & TexCoord0) != 0)
158     {
159         vertices[n++].f = v.texCoords[0].x;
160         vertices[n++].f = v.texCoords[0].y;
161     }
162     if ((parts & TexCoord1) != 0)
163     {
164         vertices[n++].f = v.texCoords[1].x;
165         vertices[n++].f = v.texCoords[1].y;
166     }
167 
168     bbox.include(v.point);
169 
170     nVertices++;
171 }
172 
173 
getBoundingBox() const174 AxisAlignedBox VertexList::getBoundingBox() const
175 {
176     return bbox;
177 }
178 
179 
getDiffuseColor() const180 Color VertexList::getDiffuseColor() const
181 {
182     return diffuseColor;
183 }
184 
setDiffuseColor(Color color)185 void VertexList::setDiffuseColor(Color color)
186 {
187     diffuseColor = color;
188 }
189 
getSpecularColor() const190 Color VertexList::getSpecularColor() const
191 {
192     return specularColor;
193 }
194 
setSpecularColor(Color color)195 void VertexList::setSpecularColor(Color color)
196 {
197     specularColor = color;
198 }
199 
getShininess() const200 float VertexList::getShininess() const
201 {
202     return shininess;
203 }
204 
setShininess(float _shininess)205 void VertexList::setShininess(float _shininess)
206 {
207     shininess = _shininess;
208 }
209 
getTexture() const210 ResourceHandle VertexList::getTexture() const
211 {
212     return texture;
213 }
214 
setTexture(ResourceHandle _texture)215 void VertexList::setTexture(ResourceHandle _texture)
216 {
217     texture = _texture;
218 }
219 
220 
221 // Apply a translation and uniform scale to the vertices
transform(Vec3f translation,float scale)222 void VertexList::transform(Vec3f translation, float scale)
223 {
224     for (uint32 i = 0; i < nVertices; i++)
225     {
226         uint32 n = i * vertexSize;
227         Vec3f tv = (Vec3f(vertices[n].f, vertices[n + 1].f, vertices[n + 2].f) + translation) * scale;
228         vertices[n    ].f = tv.x;
229         vertices[n + 1].f = tv.y;
230         vertices[n + 2].f = tv.z;
231     }
232 
233     // Transform the bounding box
234     Point3f mn = bbox.getMinimum();
235     Point3f mx = bbox.getMaximum();
236     Point3f tr(-translation.x, -translation.y, -translation.z);
237     bbox = AxisAlignedBox(Point3f(0, 0, 0) + ((mn - tr) * scale),
238                           Point3f(0, 0, 0) + ((mx - tr) * scale));
239 }
240 
241 
pick(const Ray3d & ray,double & distance)242 bool VertexList::pick(const Ray3d& ray, double& distance)
243 {
244     double maxDistance = 1.0e30;
245     double closest = maxDistance;
246 
247     uint32 k = 0;
248     for (uint32 i = 0; i < nVertices; i += 3)
249     {
250         // Get the triangle vertices v0, v1, and v2
251         Point3d v0(vertices[k + 0].f, vertices[k + 1].f, vertices[k + 2].f);
252         k += vertexSize;
253         Point3d v1(vertices[k + 0].f, vertices[k + 1].f, vertices[k + 2].f);
254         k += vertexSize;
255         Point3d v2(vertices[k + 0].f, vertices[k + 1].f, vertices[k + 2].f);
256         k += vertexSize;
257 
258         // Compute the edge vectors e0 and e1, and the normal n
259         Vec3d e0 = v1 - v0;
260         Vec3d e1 = v2 - v0;
261         Vec3d n = e0 ^ e1;
262 
263         // c is the cosine of the angle between the ray and triangle normal
264         double c = n * ray.direction;
265 
266         // If the ray is parallel to the triangle, it either misses the
267         // triangle completely, or is contained in the triangle's plane.
268         // If it's contained in the plane, we'll still call it a miss.
269         if (c != 0.0)
270         {
271             double t = (n * (v0 - ray.origin)) / c;
272             if (t < closest && t > 0.0)
273             {
274                 double m00 = e0 * e0;
275                 double m01 = e0 * e1;
276                 double m10 = e1 * e0;
277                 double m11 = e1 * e1;
278                 double det = m00 * m11 - m01 * m10;
279                 if (det != 0.0)
280                 {
281                     Point3d p = ray.point(t);
282                     Vec3d q = p - v0;
283                     double q0 = e0 * q;
284                     double q1 = e1 * q;
285                     double d = 1.0 / det;
286                     double s0 = (m11 * q0 - m01 * q1) * d;
287                     double s1 = (m00 * q1 - m10 * q0) * d;
288                     if (s0 >= 0.0 && s1 >= 0.0 && s0 + s1 <= 1.0)
289                         closest = t;
290                 }
291             }
292         }
293     }
294 
295     if (closest != maxDistance)
296     {
297         distance = closest;
298         return true;
299     }
300     else
301     {
302         return false;
303     }
304 }
305 
306 
getVertexParts() const307 uint32 VertexList::getVertexParts() const
308 {
309     return parts;
310 }
311 
312 
getVertexData() const313 void* VertexList::getVertexData() const
314 {
315     return reinterpret_cast<void*>(vertices);
316 }
317 
318 
getVertexCount() const319 uint32 VertexList::getVertexCount() const
320 {
321     return nVertices;
322 }
323