]> git.mxchange.org Git - simgear.git/blob - simgear/scene/util/PrimitiveUtils.cxx
Work around apparent OSG 3.2.0 normal binding bug.
[simgear.git] / simgear / scene / util / PrimitiveUtils.cxx
1 /* -*-c++-*-
2  *
3  * Copyright (C) 2009 Tim Moore
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 as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
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.
14  *
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,
18  * MA 02110-1301, USA.
19  *
20  */
21
22 #include "PrimitiveUtils.hxx"
23 #include <iostream>
24 using namespace osg;
25
26 namespace
27 {
28 class GetPrimitive : public PrimitiveFunctor
29 {
30 public:
31     simgear::Primitive result;
32     GetPrimitive(unsigned int primitiveIndex)
33         : _primitiveIndex(primitiveIndex), _primitivesSeen(0),
34           _vertexArrayPtr(0), _modeCache(0)
35     {
36         result.numVerts = 0;
37     }
38     
39     virtual void setVertexArray(unsigned int,const Vec2*)
40     {
41         notify(WARN)<<"GetPrimitive does not support Vec2* vertex arrays"<<std::endl;
42     }
43
44     virtual void setVertexArray(unsigned int count,const Vec3* vertices)
45     {
46         _vertexArrayPtr = vertices;
47     }
48
49     virtual void setVertexArray(unsigned int,const Vec4* )
50     {
51         notify(WARN)<<"GetPrimitive does not support Vec4* vertex arrays"<<std::endl;
52     }
53
54     virtual void setVertexArray(unsigned int,const Vec2d*)
55     {
56         notify(WARN)<<"GetPrimitive does not support Vec2d* vertex arrays"<<std::endl;
57     }
58
59     virtual void setVertexArray(unsigned int,const Vec3d*)
60     {
61         notify(WARN)<<"GetPrimitive does not support Vec3d* vertex arrays"<<std::endl;
62     }
63
64     virtual void setVertexArray(unsigned int,const Vec4d* )
65     {
66         notify(WARN)<<"GetPrimitive does not support Vec4d* vertex arrays"<<std::endl;
67     }
68     
69     void drawArrays(GLenum mode_, GLint first, GLsizei count)
70     {
71         if (_primitiveIndex < _primitivesSeen) {
72             return;
73         }
74         int numPrims = getNumPrims(mode_, count);
75         if (_primitivesSeen + numPrims < _primitiveIndex) {
76             _primitivesSeen += numPrims;
77             return;
78         }
79         int primInSet = _primitiveIndex - _primitivesSeen;
80         switch (mode_) {
81         case GL_POINTS:
82             result.numVerts = 1;
83             result.vertices[0] = _vertexArrayPtr[first + primInSet];
84             break;
85         case GL_LINES:
86             result.numVerts = 2;
87             result.vertices[0] = _vertexArrayPtr[first + primInSet * 2];
88             result.vertices[1] = _vertexArrayPtr[first + primInSet * 2 + 1];
89             break;
90         case GL_TRIANGLES:
91             result.numVerts = 3;
92             for (int i = 0; i < 3; ++i)
93                 result.vertices[i] = _vertexArrayPtr[first + primInSet * 3 + i];
94             break;
95         case GL_QUADS:
96             result.numVerts = 4;
97             for (int i = 0; i < 4; ++i)
98                 result.vertices[i] = _vertexArrayPtr[first + primInSet * 4 + i];
99             break;
100         case GL_LINE_STRIP:
101             result.numVerts = 2;
102             result.vertices[0] = _vertexArrayPtr[first + primInSet];
103             result.vertices[1] = _vertexArrayPtr[first + primInSet + 1];
104             break;
105         case GL_LINE_LOOP:
106             result.numVerts = 2;
107             if (primInSet < numPrims - 1) {
108                 result.vertices[0] = _vertexArrayPtr[first + primInSet];
109                 result.vertices[1] = _vertexArrayPtr[first + primInSet + 1];
110             } else {
111                 result.vertices[0] = _vertexArrayPtr[first + count - 1];
112                 result.vertices[1] = _vertexArrayPtr[first];
113             }
114             break;
115         case GL_TRIANGLE_STRIP:
116             result.numVerts = 3;
117                 result.vertices[0] = _vertexArrayPtr[first + primInSet];
118             if (primInSet % 2) {
119                 result.vertices[1] = _vertexArrayPtr[first + primInSet + 2];
120                 result.vertices[2] = _vertexArrayPtr[first + primInSet + 1];
121             } else {
122                 result.vertices[1] = _vertexArrayPtr[first + primInSet + 1];
123                 result.vertices[2] = _vertexArrayPtr[first + primInSet + 2];
124             }
125             break;
126         case GL_TRIANGLE_FAN:
127         case GL_POLYGON:
128             result.numVerts = 3;
129             result.vertices[0] = _vertexArrayPtr[first];
130             result.vertices[1] = _vertexArrayPtr[first + 1 + primInSet];
131             result.vertices[2] = _vertexArrayPtr[first + 1 + primInSet + 1];
132             break;
133         case GL_QUAD_STRIP:
134             result.numVerts = 4;
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];
139             break;
140         default:
141             break;
142         }
143         _primitivesSeen += numPrims;        
144     }
145
146     template<class IndexType>
147     void drawElementsTemplate(GLenum mode_, GLsizei count,
148                               const IndexType* indices)
149     {
150         if (_primitiveIndex < _primitivesSeen) {
151             return;
152         }
153         int numPrims = getNumPrims(mode_, count);
154         if (_primitivesSeen + numPrims < _primitiveIndex) {
155             _primitivesSeen += numPrims;
156             return;
157         }
158         int primInSet = _primitiveIndex - _primitivesSeen;
159         switch (mode_) {
160         case GL_POINTS:
161             result.numVerts = 1;            
162             result.vertices[0] = _vertexArrayPtr[indices[primInSet]];
163             break;
164         case GL_LINES:
165             result.numVerts = 2;            
166             result.vertices[0] = _vertexArrayPtr[indices[primInSet * 2]];
167             result.vertices[1] = _vertexArrayPtr[indices[primInSet * 2 + 1]];
168             break;
169         case GL_TRIANGLES:
170             result.numVerts = 3;            
171             for (int i = 0; i < 3; ++i)
172                 result.vertices[i] = _vertexArrayPtr[indices[primInSet * 3 + i]];
173             break;
174         case GL_QUADS:
175             result.numVerts = 4;            
176             for (int i = 0; i < 4; ++i)
177                 result.vertices[i] = _vertexArrayPtr[indices[primInSet * 4 + i]];
178             break;
179         case GL_LINE_STRIP:
180             result.numVerts = 2;            
181             result.vertices[0] = _vertexArrayPtr[indices[primInSet]];
182             result.vertices[1] = _vertexArrayPtr[indices[primInSet + 1]];
183             break;
184         case GL_LINE_LOOP:
185             result.numVerts = 2;            
186             if (primInSet < numPrims - 1) {
187                 result.vertices[0] = _vertexArrayPtr[indices[primInSet]];
188                 result.vertices[1] = _vertexArrayPtr[indices[primInSet + 1]];
189             } else {
190                 result.vertices[0] = _vertexArrayPtr[indices[count - 1]];
191                 result.vertices[1] = _vertexArrayPtr[indices[0]];
192             }
193             break;
194         case GL_TRIANGLE_STRIP:
195             result.numVerts = 3;            
196                 result.vertices[0] = _vertexArrayPtr[indices[primInSet]];
197             if (primInSet % 2) {
198                 result.vertices[1] = _vertexArrayPtr[indices[primInSet + 2]];
199                 result.vertices[2] = _vertexArrayPtr[indices[primInSet + 1]];
200             } else {
201                 result.vertices[1] = _vertexArrayPtr[indices[primInSet + 1]];
202                 result.vertices[2] = _vertexArrayPtr[indices[primInSet + 2]];
203             }
204             break;
205         case GL_TRIANGLE_FAN:
206         case GL_POLYGON:
207             result.numVerts = 3;            
208             result.vertices[0] = _vertexArrayPtr[indices[0]];
209             result.vertices[1] = _vertexArrayPtr[indices[1 + primInSet]];
210             result.vertices[2] = _vertexArrayPtr[indices[1 + primInSet + 1]];
211             break;
212         case GL_QUAD_STRIP:
213             result.numVerts = 4;            
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]];
218             break;
219         default:
220             break;
221         }
222         _primitivesSeen += numPrims;        
223     }
224
225     void drawElements(GLenum mode_, GLsizei count, const GLubyte* indices)
226     {
227         drawElementsTemplate(mode_, count, indices);
228     }
229
230     void drawElements(GLenum mode_, GLsizei count, const GLushort* indices)
231     {
232         drawElementsTemplate(mode_, count, indices);
233     }
234
235     void drawElements(GLenum mode_,GLsizei count,const GLuint* indices)
236     {
237         drawElementsTemplate(mode_, count, indices);
238     }
239
240     virtual void begin(GLenum mode)
241     {
242         _modeCache = mode;
243         _vertexCache.clear();
244     }
245
246     void vertex(const Vec2& vert)
247     {
248         _vertexCache.push_back(osg::Vec3(vert[0],vert[1],0.0f));
249     }
250     void vertex(const Vec3& vert)
251     {
252         _vertexCache.push_back(vert);
253     }
254     void vertex(const Vec4& vert)
255     {
256         _vertexCache.push_back(osg::Vec3(vert[0],vert[1],vert[2])/vert[3]);
257     }
258     void vertex(float x,float y)
259     {
260         _vertexCache.push_back(osg::Vec3(x,y,0.0f));
261     }
262     void vertex(float x,float y,float z)
263     {
264         _vertexCache.push_back(osg::Vec3(x,y,z));
265     }
266     void vertex(float x,float y,float z,float w)
267     {
268         _vertexCache.push_back(osg::Vec3(x,y,z)/w);
269     
270     }
271     
272     void end()
273     {
274         if (!_vertexCache.empty()) {
275             const Vec3* oldVert = _vertexArrayPtr;
276             setVertexArray(_vertexCache.size(), &_vertexCache.front());
277             drawArrays(_modeCache, 0, _vertexCache.size());
278             _vertexArrayPtr = oldVert;
279         }
280     }
281     
282 protected:
283     int getNumPrims(GLenum mode, int count)
284     {
285         switch (mode) {
286         case GL_POINTS:
287             return count;
288         case GL_LINES:
289             return count / 2;
290         case GL_TRIANGLES:
291             return count / 3;
292         case GL_QUADS:
293             return count / 4;
294         case GL_LINE_STRIP:
295             return count - 1;
296         case GL_LINE_LOOP:
297             return count;
298         case GL_TRIANGLE_STRIP:
299             return count - 2;
300         case GL_TRIANGLE_FAN:
301         case GL_POLYGON:
302             return count - 2;
303         case GL_QUAD_STRIP:
304             return (count - 2) / 2;
305         default:
306             std::cerr << "FATAL: unknown GL mode " << mode << std::endl;
307             throw new std::exception();
308         }
309     }
310     unsigned _primitiveIndex;
311     unsigned _primitivesSeen;
312     const Vec3* _vertexArrayPtr;
313     GLenum _modeCache;
314     std::vector<Vec3>  _vertexCache;
315 };
316 }
317
318 namespace simgear
319 {
320 Primitive getPrimitive(Drawable* drawable, unsigned primitiveIndex)
321 {
322     GetPrimitive getPrim(primitiveIndex);
323     drawable->accept(getPrim);
324     return getPrim.result;
325 }
326 }