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