1 #include "ObjRenderer.h"
2 #include "SyntopiaCore/Logging/Logging.h"
3 
4 using namespace SyntopiaCore::Math;
5 using namespace SyntopiaCore::GLEngine;
6 using namespace SyntopiaCore::Logging;
7 
8 namespace StructureSynth {
9 	namespace Model {
10 		namespace Rendering {
11 
12 
addGroup(ObjGroup g)13 			void ObjGroup::addGroup(ObjGroup g) {
14 				int vertexCount = vertices.count();
15 				int normalCount = normals.count();
16 
17 				for (int i = 0; i < g.vertices.count(); i++) {
18 					vertices.append(g.vertices[i]);
19 				}
20 
21 				for (int i = 0; i < g.normals.count(); i++) {
22 					normals.append(g.normals[i]);
23 				}
24 
25 				for (int i = 0; i < g.faces.count(); i++) {
26 					for (int j = 0; j < g.faces[i].count(); j++) {
27 						g.faces[i][j].vID = g.faces[i][j].vID + vertexCount;
28 						g.faces[i][j].nID = g.faces[i][j].nID + normalCount;
29 					}
30 					faces.append(g.faces[i]);
31 				}
32 			}
33 
34 			// Removes redundant vertices.
reduceVertices()35 			void ObjGroup::reduceVertices() {
36 				QVector<Vector3f> newVertices;
37 				QVector<Vector3f> newNormals;
38 				QMap<int,int> oldToNewVertex;
39 				QMap<int,int> oldToNewNormals;
40 
41 				// Reduce vertices and normals (if present)
42 				for (int i = 0; i < vertices.count(); i++) {
43 					int index = newVertices.indexOf(vertices[i]);
44 					if (index==-1) {
45 						newVertices.append(vertices[i]);
46 						index=newVertices.count()-1;
47 					}
48 					oldToNewVertex[i] = index;
49 				}
50 
51 				// Reduce vertices and normals (if present)
52 				for (int i = 0; i < normals.count(); i++) {
53 					int index = newNormals.indexOf(normals[i]);
54 					if (index==-1) {
55 						newNormals.append(normals[i]);
56 						index=newNormals.count()-1;
57 					}
58 					oldToNewNormals[i] = index;
59 				}
60 
61 
62 				// Update indices
63 				for (int i = 0; i < faces.count(); i++) {
64 					for (int j = 0; j < faces[i].count(); j++) {
65 						faces[i][j].vID = oldToNewVertex[faces[i][j].vID-1]+1; // beware OBJ is 1-based!
66 						faces[i][j].nID = oldToNewNormals[faces[i][j].nID-1]+1;
67 					}
68 				}
69 
70 				vertices = newVertices;
71 				normals = newNormals;
72 			}
73 
74 			namespace {
75 				/*
76 				This function was taken from Paul Bourkes website:
77 				http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/sphere_cylinder/
78 
79 				Create a unit sphere centered at the origin
80 				This code illustrates the concept rather than implements it efficiently
81 				It is called with two arguments, the theta and phi angle increments in degrees
82 				Note that at the poles only 3 vertex facet result
83 				while the rest of the sphere has 4 point facets
84 				*/
CreateUnitSphere(int dt,int dp,ObjGroup & motherGroup,Matrix4f m)85 				void CreateUnitSphere(int dt,int dp, ObjGroup& motherGroup, Matrix4f m)
86 				{
87 					float DTOR = 3.1415/180.0;
88 					double dtheta = 180.0/dt;
89 					double dphi = 360.0/dp;
90 					ObjGroup group;
91 					for (int i = 0; i < dt; i++) {
92 						double theta = -90.0 + ((i*180.0)/(double)dt);
93 						for (int j=0;j<dp;j++) {
94 							double phi = ((j*360.0)/(double)dp);
95 							int vi = group.vertices.count()+1;
96 							int vn = group.normals.count()+1;
97 
98 							group.vertices.append(m*Vector3f(cos(theta*DTOR) * cos(phi*DTOR), cos(theta*DTOR) * sin(phi*DTOR), sin(theta*DTOR)));
99 							group.normals.append(Vector3f(cos(theta*DTOR) * cos(phi*DTOR), cos(theta*DTOR) * sin(phi*DTOR), sin(theta*DTOR)));
100 
101 							QVector<VertexNormal> vns;
102 							if (theta > -90 && theta < 90) {
103 								group.vertices.append(m*Vector3f( cos(theta*DTOR) * cos((phi+dphi)*DTOR),cos(theta*DTOR) * sin((phi+dphi)*DTOR),  sin(theta*DTOR)));
104 								group.normals.append(Vector3f( cos(theta*DTOR) * cos((phi+dphi)*DTOR),cos(theta*DTOR) * sin((phi+dphi)*DTOR),  sin(theta*DTOR)));
105 								for (int j = 0; j<4; j++) vns.append(VertexNormal(j+vi,j+vn));
106 							} else {
107 								for (int j = 0; j<3; j++) vns.append(VertexNormal(j+vi,j+vn));
108 							}
109 							group.vertices.append(m*Vector3f( cos((theta+dtheta)*DTOR) * cos((phi+dphi)*DTOR),	cos((theta+dtheta)*DTOR) * sin((phi+dphi)*DTOR), sin((theta+dtheta)*DTOR)));
110 							group.normals.append(Vector3f( cos((theta+dtheta)*DTOR) * cos((phi+dphi)*DTOR),	cos((theta+dtheta)*DTOR) * sin((phi+dphi)*DTOR), sin((theta+dtheta)*DTOR)));
111 							group.vertices.append(m*Vector3f(cos((theta+dtheta)*DTOR) * cos(phi*DTOR), cos((theta+dtheta)*DTOR) * sin(phi*DTOR), sin((theta+dtheta)*DTOR)));
112 							group.normals.append(Vector3f(cos((theta+dtheta)*DTOR) * cos(phi*DTOR), cos((theta+dtheta)*DTOR) * sin(phi*DTOR), sin((theta+dtheta)*DTOR)));
113 							group.faces.append(vns);
114 						}
115 					}
116 					group.reduceVertices();
117 					motherGroup.addGroup(group);
118 				}
119 
120 			}
121 
addLineQuad(ObjGroup & group,Vector3f v1,Vector3f v2,Vector3f v3,Vector3f v4)122 			void ObjRenderer::addLineQuad(ObjGroup& group, Vector3f v1,Vector3f v2,Vector3f v3,Vector3f v4) {
123 				int vi = group.vertices.count()+1;
124 				group.vertices.append(v1);
125 				group.vertices.append(v2);
126 				group.vertices.append(v3);
127 				group.vertices.append(v4);
128 
129 				for (int j = 0; j<4; j++) {
130 					QVector<VertexNormal> vns;
131 					vns.append(VertexNormal(vi+j, -1));
132 					vns.append(VertexNormal(vi+(j+1 % 4), -1));
133 					group.faces.append(vns);
134 				}
135 			}
136 
137 
addQuad(ObjGroup & group,Vector3f v1,Vector3f v2,Vector3f v3,Vector3f v4)138 			void ObjRenderer::addQuad(ObjGroup& group, Vector3f v1,Vector3f v2,Vector3f v3,Vector3f v4) {
139 				int vi = group.vertices.count()+1;
140 				int vn = group.normals.count()+1;
141 				group.vertices.append(v1);
142 				group.vertices.append(v2);
143 				group.vertices.append(v3);
144 				group.vertices.append(v4);
145 
146 				Vector3f normal = Vector3f::cross((v2-v1), (v4-v1)).normalized();
147 				group.normals.append(normal);
148 				group.normals.append(normal);
149 				group.normals.append(normal);
150 				group.normals.append(normal);
151 
152 				QVector<VertexNormal> vns;
153 				for (int j = 0; j<4; j++) vns.append(VertexNormal(vi+j, vn+j));
154 				group.faces.append(vns);
155 			}
156 
setClass(QString classID,Vector3f rgb,double)157 			void ObjRenderer::setClass(QString classID, Vector3f rgb, double /*alpha*/) {
158 				// Should we also group by alpha channel?
159 				QString className;
160 				if (groupByTagging) className += classID;
161 				if (groupByColor) className += QColor(int(rgb[0]*255),int(rgb[1]*255),int(rgb[2]*255)).name();
162 				if (className.isEmpty()) className = "default";
163 				if (!groups.contains(className)) groups[className] = ObjGroup();
164 				groups[className].groupName = className;
165 				currentGroup = className;
166 			}
167 
168 
drawBox(SyntopiaCore::Math::Vector3f O,SyntopiaCore::Math::Vector3f v1,SyntopiaCore::Math::Vector3f v2,SyntopiaCore::Math::Vector3f v3,PrimitiveClass * classID)169 			void ObjRenderer::drawBox(SyntopiaCore::Math::Vector3f O,
170 				SyntopiaCore::Math::Vector3f v1 ,
171 				SyntopiaCore::Math::Vector3f v2,
172 				SyntopiaCore::Math::Vector3f v3, PrimitiveClass* classID) {
173 					setClass(classID->name,rgb,alpha);
174 					ObjGroup group;
175 					addQuad(group, O, O+v2,O+v2+v1,O+v1);
176 					addQuad(group, O+v3, O+v1+v3, O+v2+v1+v3, O+v2+v3);
177 					addQuad(group, O, O+v3, O+v3+v2,O+v2);
178 					addQuad(group, O+v1,O+v2+v1, O+v3+v2+v1,  O+v3+v1);
179 					addQuad(group, O, O+v1, O+v3+v1, O+v3);
180 					addQuad(group, O+v2, O+v3+v2 , O+v3+v2+v1,O+v1+v2);
181 					group.reduceVertices();
182 					groups[currentGroup].addGroup(group);
183 			};
184 
185 
drawMesh(SyntopiaCore::Math::Vector3f O,SyntopiaCore::Math::Vector3f v1,SyntopiaCore::Math::Vector3f v2,SyntopiaCore::Math::Vector3f endBase,SyntopiaCore::Math::Vector3f u1,SyntopiaCore::Math::Vector3f u2,PrimitiveClass * classID)186 			void ObjRenderer::drawMesh(  SyntopiaCore::Math::Vector3f O,
187 				SyntopiaCore::Math::Vector3f v1,
188 				SyntopiaCore::Math::Vector3f v2,
189 				SyntopiaCore::Math::Vector3f endBase,
190 				SyntopiaCore::Math::Vector3f u1,
191 				SyntopiaCore::Math::Vector3f u2,
192 				PrimitiveClass* classID) {
193 
194 					setClass(classID->name,rgb,alpha);
195 					ObjGroup group;
196 					Vector3f v3 = endBase-O;
197 					addQuad(group, O, O+v2,O+v2+v1,O+v1);
198 					addQuad(group, O+v3, O+u1+v3, O+u2+u1+v3, O+u2+v3);
199 					addQuad(group, O, O+v3, O+v3+u2,O+v2);
200 					addQuad(group, O+v1,O+v2+v1, O+v3+u2+u1,  O+v3+u1);
201 					addQuad(group, O, O+v1, O+v3+u1, O+v3);
202 					addQuad(group, O+v2, O+v3+u2 , O+v3+u2+u1,O+v1+v2);
203 					group.reduceVertices();
204 					groups[currentGroup].addGroup(group);
205 
206 			};
207 
drawGrid(SyntopiaCore::Math::Vector3f O,SyntopiaCore::Math::Vector3f v1,SyntopiaCore::Math::Vector3f v2,SyntopiaCore::Math::Vector3f v3,PrimitiveClass * classID)208 			void ObjRenderer::drawGrid(SyntopiaCore::Math::Vector3f O,
209 				SyntopiaCore::Math::Vector3f v1 ,
210 				SyntopiaCore::Math::Vector3f v2,
211 				SyntopiaCore::Math::Vector3f v3,
212 				PrimitiveClass* classID) {
213 					setClass(classID->name,rgb,alpha);
214 					ObjGroup group;
215 					addLineQuad(group,O, O+v2,O+v2+v1,O+v1);
216 					addLineQuad(group,O+v3, O+v1+v3, O+v2+v1+v3, O+v2+v3);
217 					addLineQuad(group,O, O+v3, O+v3+v2,O+v2);
218 					addLineQuad(group,O+v1,O+v2+v1, O+v3+v2+v1,  O+v3+v1);
219 					addLineQuad(group,O, O+v1, O+v3+v1, O+v3);
220 					addLineQuad(group,O+v2, O+v3+v2 , O+v3+v2+v1,O+v1+v2);
221 					group.reduceVertices();
222 					groups[currentGroup].addGroup(group);
223 			};
224 
drawLine(SyntopiaCore::Math::Vector3f from,SyntopiaCore::Math::Vector3f to,PrimitiveClass * classID)225 			void ObjRenderer::drawLine(SyntopiaCore::Math::Vector3f from, SyntopiaCore::Math::Vector3f to, PrimitiveClass* classID) {
226 				setClass(classID->name,rgb,alpha);
227 				ObjGroup group;
228 				group.vertices.append(from);
229 				group.vertices.append(to);
230 				QVector<VertexNormal> vns;
231 				vns.append(VertexNormal(1, -1));
232 				vns.append(VertexNormal(2, -1));
233 				group.faces.append(vns);
234 				groups[currentGroup].addGroup(group);
235 			};
236 
drawTriangle(SyntopiaCore::Math::Vector3f p1,SyntopiaCore::Math::Vector3f p2,SyntopiaCore::Math::Vector3f p3,PrimitiveClass * classID)237 			void ObjRenderer::drawTriangle(SyntopiaCore::Math::Vector3f p1,
238 				SyntopiaCore::Math::Vector3f p2,
239 				SyntopiaCore::Math::Vector3f p3,
240 				PrimitiveClass* classID)
241 			{
242 					setClass(classID->name,rgb,alpha);
243 					ObjGroup group;
244 					group.vertices.append(p1);
245 					group.vertices.append(p2);
246 					group.vertices.append(p3);
247 
248 					QVector<VertexNormal> vns;
249 					for (int j = 0; j<3; j++) vns.append(VertexNormal(1+j, -1));
250 					group.faces.append(vns);
251 					groups[currentGroup].addGroup(group);
252 			}
253 
drawDot(SyntopiaCore::Math::Vector3f v,PrimitiveClass * classID)254 			void ObjRenderer::drawDot(SyntopiaCore::Math::Vector3f v, PrimitiveClass* classID) {
255 				setClass(classID->name,rgb,alpha);
256 				ObjGroup group;
257 				group.vertices.append(v);
258 				QVector<VertexNormal> vns;
259 				vns.append(VertexNormal(1, -1));
260 				group.faces.append(vns);
261 				groups[currentGroup].addGroup(group);
262 			};
263 
drawSphere(SyntopiaCore::Math::Vector3f center,float radius,PrimitiveClass * classID)264 			void ObjRenderer::drawSphere(SyntopiaCore::Math::Vector3f center, float radius, PrimitiveClass* classID) {
265 				setClass(classID->name,rgb,alpha);
266 
267 				Matrix4f m  = Matrix4f::Translation(center.x(),center.y(),center.z())*(Matrix4f::ScaleMatrix(radius));
268 
269 				CreateUnitSphere(sphereDT,sphereDP,groups[currentGroup],m);
270 			};
271 
begin()272 			void ObjRenderer::begin() {
273 				rgb = Vector3f(1,0,0);
274 				alpha = 1;
275 			};
276 
end()277 			void ObjRenderer::end() {
278 			};
279 
280 
writeToStream(QTextStream & ts)281 			void ObjRenderer::writeToStream(QTextStream& ts) {
282 				int vertexCount = 0;
283 				int normalCount = 0;
284 
285 				foreach (ObjGroup o, groups) {
286 					// Group name
287 					INFO(o.groupName);
288 					ts << "g " << o.groupName << endl;
289 					ts << "usemtl " << o.groupName << endl;
290 
291 					// Vertices
292 					foreach (Vector3f v, o.vertices) {
293 						ts << "v "	<< QString::number(v.x()) << " "
294 							<< QString::number(v.y())  << " "
295 							<< QString::number(v.z())  << " "
296 							<< endl;
297 					}
298 
299 					// Normals
300 					foreach (Vector3f v, o.normals) {
301 						ts << "vn "	<< QString::number(v.x()) << " "
302 							<< QString::number(v.y())  << " "
303 							<< QString::number(v.z())  << " "
304 							<< endl;
305 					}
306 
307 					// Faces
308 					foreach (QVector<VertexNormal> vi, o.faces) {
309 						if (vi.count() == 1) {
310 							ts << "p ";
311 						} else if (vi.count() == 2) {
312 							ts << "l ";
313 						} else {
314 							ts << "f ";
315 						}
316 						foreach (VertexNormal vn, vi) {
317 							if (vn.nID == -1) {
318 								ts << QString::number(vn.vID+vertexCount) << " ";
319 							} else {
320 								ts << QString::number(vn.vID+vertexCount) << "//"
321 									<< QString::number(vn.nID+normalCount) << " ";
322 							}
323 						}
324 						ts << endl;
325 
326 					}
327 					vertexCount += o.vertices.count();
328 					normalCount += o.normals.count();
329 				}
330 			};
331 
332 
333 
334 
335 		}
336 	}
337 }
338 
339