3 * Copyright (C) 2009 Tim Moore
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 #include "PrimitiveUtils.hxx"
28 class GetPrimitive : public PrimitiveFunctor
31 simgear::Primitive result;
32 GetPrimitive(unsigned int primitiveIndex)
33 : _primitiveIndex(primitiveIndex), _primitivesSeen(0),
34 _vertexArrayPtr(0), _modeCache(0)
39 virtual void setVertexArray(unsigned int,const Vec2*)
41 notify(WARN)<<"GetPrimitive does not support Vec2* vertex arrays"<<std::endl;
44 virtual void setVertexArray(unsigned int count,const Vec3* vertices)
46 _vertexArrayPtr = vertices;
49 virtual void setVertexArray(unsigned int,const Vec4* )
51 notify(WARN)<<"GetPrimitive does not support Vec4* vertex arrays"<<std::endl;
54 virtual void setVertexArray(unsigned int,const Vec2d*)
56 notify(WARN)<<"GetPrimitive does not support Vec2d* vertex arrays"<<std::endl;
59 virtual void setVertexArray(unsigned int,const Vec3d*)
61 notify(WARN)<<"GetPrimitive does not support Vec3d* vertex arrays"<<std::endl;
64 virtual void setVertexArray(unsigned int,const Vec4d* )
66 notify(WARN)<<"GetPrimitive does not support Vec4d* vertex arrays"<<std::endl;
69 void drawArrays(GLenum mode_, GLint first, GLsizei count)
71 if (_primitiveIndex < _primitivesSeen) {
74 int numPrims = getNumPrims(mode_, count);
75 if (_primitivesSeen + numPrims < _primitiveIndex) {
76 _primitivesSeen += numPrims;
79 int primInSet = _primitiveIndex - _primitivesSeen;
83 result.vertices[0] = _vertexArrayPtr[first + primInSet];
87 result.vertices[0] = _vertexArrayPtr[first + primInSet * 2];
88 result.vertices[1] = _vertexArrayPtr[first + primInSet * 2 + 1];
92 for (int i = 0; i < 3; ++i)
93 result.vertices[i] = _vertexArrayPtr[first + primInSet * 3 + i];
97 for (int i = 0; i < 4; ++i)
98 result.vertices[i] = _vertexArrayPtr[first + primInSet * 4 + i];
102 result.vertices[0] = _vertexArrayPtr[first + primInSet];
103 result.vertices[1] = _vertexArrayPtr[first + primInSet + 1];
107 if (primInSet < numPrims - 1) {
108 result.vertices[0] = _vertexArrayPtr[first + primInSet];
109 result.vertices[1] = _vertexArrayPtr[first + primInSet + 1];
111 result.vertices[0] = _vertexArrayPtr[first + count - 1];
112 result.vertices[1] = _vertexArrayPtr[first];
115 case GL_TRIANGLE_STRIP:
117 result.vertices[0] = _vertexArrayPtr[first + primInSet];
119 result.vertices[1] = _vertexArrayPtr[first + primInSet + 2];
120 result.vertices[2] = _vertexArrayPtr[first + primInSet + 1];
122 result.vertices[1] = _vertexArrayPtr[first + primInSet + 1];
123 result.vertices[2] = _vertexArrayPtr[first + primInSet + 2];
126 case GL_TRIANGLE_FAN:
129 result.vertices[0] = _vertexArrayPtr[first];
130 result.vertices[1] = _vertexArrayPtr[first + 1 + primInSet];
131 result.vertices[2] = _vertexArrayPtr[first + 1 + primInSet + 1];
135 result.vertices[0] = _vertexArrayPtr[first + primInSet / 2];
136 result.vertices[1] = _vertexArrayPtr[first + primInSet / 2 + 1];
137 result.vertices[2] = _vertexArrayPtr[first + primInSet / 2 + 3];
138 result.vertices[3] = _vertexArrayPtr[first + primInSet / 2 + 2];
143 _primitivesSeen += numPrims;
146 template<class IndexType>
147 void drawElementsTemplate(GLenum mode_, GLsizei count,
148 const IndexType* indices)
150 if (_primitiveIndex < _primitivesSeen) {
153 int numPrims = getNumPrims(mode_, count);
154 if (_primitivesSeen + numPrims < _primitiveIndex) {
155 _primitivesSeen += numPrims;
158 int primInSet = _primitiveIndex - _primitivesSeen;
162 result.vertices[0] = _vertexArrayPtr[indices[primInSet]];
166 result.vertices[0] = _vertexArrayPtr[indices[primInSet * 2]];
167 result.vertices[1] = _vertexArrayPtr[indices[primInSet * 2 + 1]];
171 for (int i = 0; i < 3; ++i)
172 result.vertices[i] = _vertexArrayPtr[indices[primInSet * 3 + i]];
176 for (int i = 0; i < 4; ++i)
177 result.vertices[i] = _vertexArrayPtr[indices[primInSet * 4 + i]];
181 result.vertices[0] = _vertexArrayPtr[indices[primInSet]];
182 result.vertices[1] = _vertexArrayPtr[indices[primInSet + 1]];
186 if (primInSet < numPrims - 1) {
187 result.vertices[0] = _vertexArrayPtr[indices[primInSet]];
188 result.vertices[1] = _vertexArrayPtr[indices[primInSet + 1]];
190 result.vertices[0] = _vertexArrayPtr[indices[count - 1]];
191 result.vertices[1] = _vertexArrayPtr[indices[0]];
194 case GL_TRIANGLE_STRIP:
196 result.vertices[0] = _vertexArrayPtr[indices[primInSet]];
198 result.vertices[1] = _vertexArrayPtr[indices[primInSet + 2]];
199 result.vertices[2] = _vertexArrayPtr[indices[primInSet + 1]];
201 result.vertices[1] = _vertexArrayPtr[indices[primInSet + 1]];
202 result.vertices[2] = _vertexArrayPtr[indices[primInSet + 2]];
205 case GL_TRIANGLE_FAN:
208 result.vertices[0] = _vertexArrayPtr[indices[0]];
209 result.vertices[1] = _vertexArrayPtr[indices[1 + primInSet]];
210 result.vertices[2] = _vertexArrayPtr[indices[1 + primInSet + 1]];
214 result.vertices[0] = _vertexArrayPtr[indices[primInSet / 2]];
215 result.vertices[1] = _vertexArrayPtr[indices[primInSet / 2 + 1]];
216 result.vertices[2] = _vertexArrayPtr[indices[primInSet / 2 + 3]];
217 result.vertices[3] = _vertexArrayPtr[indices[primInSet / 2 + 2]];
222 _primitivesSeen += numPrims;
225 void drawElements(GLenum mode_, GLsizei count, const GLubyte* indices)
227 drawElementsTemplate(mode_, count, indices);
230 void drawElements(GLenum mode_, GLsizei count, const GLushort* indices)
232 drawElementsTemplate(mode_, count, indices);
235 void drawElements(GLenum mode_,GLsizei count,const GLuint* indices)
237 drawElementsTemplate(mode_, count, indices);
240 virtual void begin(GLenum mode)
243 _vertexCache.clear();
246 void vertex(const Vec2& vert)
248 _vertexCache.push_back(osg::Vec3(vert[0],vert[1],0.0f));
250 void vertex(const Vec3& vert)
252 _vertexCache.push_back(vert);
254 void vertex(const Vec4& vert)
256 _vertexCache.push_back(osg::Vec3(vert[0],vert[1],vert[2])/vert[3]);
258 void vertex(float x,float y)
260 _vertexCache.push_back(osg::Vec3(x,y,0.0f));
262 void vertex(float x,float y,float z)
264 _vertexCache.push_back(osg::Vec3(x,y,z));
266 void vertex(float x,float y,float z,float w)
268 _vertexCache.push_back(osg::Vec3(x,y,z)/w);
274 if (!_vertexCache.empty()) {
275 const Vec3* oldVert = _vertexArrayPtr;
276 setVertexArray(_vertexCache.size(), &_vertexCache.front());
277 drawArrays(_modeCache, 0, _vertexCache.size());
278 _vertexArrayPtr = oldVert;
283 int getNumPrims(GLenum mode, int count)
298 case GL_TRIANGLE_STRIP:
300 case GL_TRIANGLE_FAN:
304 return (count - 2) / 2;
306 std::cerr << "FATAL: unknown GL mode " << mode << std::endl;
307 throw new std::exception();
310 unsigned _primitiveIndex;
311 unsigned _primitivesSeen;
312 const Vec3* _vertexArrayPtr;
314 std::vector<Vec3> _vertexCache;
320 Primitive getPrimitive(Drawable* drawable, unsigned primitiveIndex)
322 GetPrimitive getPrim(primitiveIndex);
323 drawable->accept(getPrim);
324 return getPrim.result;