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