1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 #include "shapenodes/soshape_trianglesort.h"
34
35 #include <cstdlib>
36 #include <cassert>
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif // HAVE_CONFIG_H
41
42 #include <Inventor/lists/SbList.h>
43 #include <Inventor/SoPrimitiveVertex.h>
44 #include <Inventor/elements/SoShapeHintsElement.h>
45 #include <Inventor/elements/SoModelMatrixElement.h>
46 #include <Inventor/elements/SoProjectionMatrixElement.h>
47 #include <Inventor/elements/SoViewingMatrixElement.h>
48 #include <Inventor/elements/SoViewVolumeElement.h>
49 #include <Inventor/bundles/SoMaterialBundle.h>
50 #include <Inventor/SbPlane.h>
51 #include <Inventor/C/tidbits.h>
52 #include <Inventor/system/gl.h>
53
soshape_trianglesort(void)54 soshape_trianglesort::soshape_trianglesort(void)
55 {
56 this->pvlist = NULL;
57 this->trianglelist = NULL;
58 }
59
~soshape_trianglesort()60 soshape_trianglesort::~soshape_trianglesort()
61 {
62 delete this->pvlist;
63 delete this->trianglelist;
64 }
65
66 void
beginShape(SoState *)67 soshape_trianglesort::beginShape(SoState *)
68 {
69 if (this->pvlist == NULL) {
70 this->pvlist = new SbList <SoPrimitiveVertex>;
71 this->trianglelist = new SbList <sorted_triangle>;
72 }
73 pvlist->truncate(0);
74 }
75
76 void
triangle(SoState *,const SoPrimitiveVertex * v1,const SoPrimitiveVertex * v2,const SoPrimitiveVertex * v3)77 soshape_trianglesort::triangle(SoState *,
78 const SoPrimitiveVertex * v1,
79 const SoPrimitiveVertex * v2,
80 const SoPrimitiveVertex * v3)
81 {
82 assert(this->pvlist);
83 this->pvlist->append(*v1);
84 this->pvlist->append(*v2);
85 this->pvlist->append(*v3);
86 }
87
88 // qsort() callback.
89 //
90 // "extern C" wrapper is needed with the OSF1/cxx compiler (probably a
91 // bug in the compiler, but it doesn't seem to hurt to do this
92 // anyway).
93 extern "C" {
94 static int
compare_triangles(const void * ptr1,const void * ptr2)95 compare_triangles(const void * ptr1, const void * ptr2)
96 {
97 soshape_trianglesort::sorted_triangle * tri1 = (soshape_trianglesort::sorted_triangle*) ptr1;
98 soshape_trianglesort::sorted_triangle * tri2 = (soshape_trianglesort::sorted_triangle*) ptr2;
99
100 if (tri1->dist > tri2->dist) return -1;
101 if (tri1->dist == tri2->dist) return tri2->backface - tri1->backface;
102 return 1;
103 }
104 }
105
106 void
endShape(SoState * state,SoMaterialBundle & mb)107 soshape_trianglesort::endShape(SoState * state, SoMaterialBundle & mb)
108 {
109 int i, n = this->pvlist->getLength() / 3;
110 if (n == 0) return;
111
112 const SoPrimitiveVertex * varray = this->pvlist->getArrayPtr();
113
114 this->trianglelist->truncate(0);
115 sorted_triangle tri;
116
117 const SoPrimitiveVertex * v;
118 const SbMatrix & mm = SoModelMatrixElement::get(state);
119
120 SoShapeHintsElement::VertexOrdering vo;
121 SoShapeHintsElement::ShapeType st;
122 SoShapeHintsElement::FaceType ft;
123 SoShapeHintsElement::get(state, vo, st, ft);
124
125 SbBool bfcull =
126 (vo != SoShapeHintsElement::UNKNOWN_ORDERING) &&
127 (st == SoShapeHintsElement::SOLID);
128
129 if (bfcull || vo == SoShapeHintsElement::UNKNOWN_ORDERING) {
130 SbPlane nearp = SoViewVolumeElement::get(state).getPlane(0.0f);
131 nearp = SbPlane(-nearp.getNormal(), -nearp.getDistanceFromOrigin());
132 // if back face culling is enabled, we can do less work
133 SbVec3f center;
134 for (i = 0; i < n; i++) {
135 int idx = i*3;
136 center.setValue(0.0f, 0.0f, 0.0f);
137 tri.idx = idx;
138 for (int j = 0; j < 3; j++) {
139 tri.backface = 0;
140 v = varray + idx + j;
141 center += v->getPoint();
142 }
143 center /= 3.0f;
144 mm.multVecMatrix(center, center);
145 tri.dist = nearp.getDistance(center);
146 trianglelist->append(tri);
147 }
148 }
149 else {
150 // project each point onto screen to find the vertex
151 // ordering of the triangle. Sort on vertex closest
152 // to the near plane.
153 SbMatrix obj2vp =
154 mm * SoViewingMatrixElement::get(state) *
155 SoProjectionMatrixElement::get(state);
156
157 int clockwise = (vo == SoShapeHintsElement::CLOCKWISE) ? 1 : 0;
158 SbVec3f c[3];
159 for (i = 0; i < n; i++) {
160 int idx = i*3;
161 tri.idx = idx;
162 // projected coordinates are between -1 and 1
163 float smalldist = 10.0f;
164 for (int j = 0; j < 3; j++) {
165 v = varray + idx + j;
166 c[j] = v->getPoint();
167 obj2vp.multVecMatrix(c[j], c[j]);
168 float dist = c[j][2];
169 if (dist < smalldist) smalldist = dist;
170 }
171 SbVec3f v0 = c[2]-c[0];
172 SbVec3f v1 = c[1]-c[0];
173 // we need only the z-component of the cross product
174 // to determine if triangle is cw or ccw
175 float cz = v0[0]*v1[1] - v0[1]*v1[0];
176 tri.backface = clockwise;
177 if (cz < 0.0f) tri.backface = 1 - clockwise;
178 tri.dist = smalldist;
179 this->trianglelist->append(tri);
180 }
181 }
182
183 const sorted_triangle * tarray = this->trianglelist->getArrayPtr();
184 qsort((void*)tarray, n, sizeof(sorted_triangle), compare_triangles);
185
186 int idx;
187
188 // this rendering loop can be optimized a lot, of course, but speed
189 // is not so important here, since it's slow to generate, copy and
190 // sort the triangles anyway.
191 glBegin(GL_TRIANGLES);
192 for (i = 0; i < n; i++) {
193 idx = tarray[i].idx;
194 v = varray + idx;
195 glTexCoord4fv(v->getTextureCoords().getValue());
196 glNormal3fv(v->getNormal().getValue());
197 mb.send(v->getMaterialIndex(), TRUE);
198 glVertex3fv(v->getPoint().getValue());
199
200 v = varray + idx+1;
201 glTexCoord4fv(v->getTextureCoords().getValue());
202 glNormal3fv(v->getNormal().getValue());
203 mb.send(v->getMaterialIndex(), TRUE);
204 glVertex3fv(v->getPoint().getValue());
205
206 v = varray + idx+2;
207 glTexCoord4fv(v->getTextureCoords().getValue());
208 glNormal3fv(v->getNormal().getValue());
209 mb.send(v->getMaterialIndex(), TRUE);
210 glVertex3fv(v->getPoint().getValue());
211 }
212 glEnd();
213 }
214