#include "Subdivision.h" #include "Renderer.h" #include #include #include Subdivision Subdivision::m_instance; void Subdivision::performSubdivision(char type) { //Step1 this->calculateVertexDegree(); //Step2 this->calculateIncidentTriangles(); //Step3 this->generateAdjacencyTable(); //Step4 this->generateLabels(); //Step5 this->generateNewVertices(); this->generateNewTriangles(); //Step 6 this->generateNewVertexCoords(type); delete Renderer::getInstance()->triangles; delete Renderer::getInstance()->points; Renderer::getInstance()->triangles = newTriangles; Renderer::getInstance()->points = newPoints; newTriangles = NULL; newPoints = NULL; labels.clear(); adjacencies.clear(); pointDegrees.clear(); for (int i = 0; i < (int) Renderer::getInstance()->points->size(); i++) { Renderer::getInstance()->points->at(i).incidentTriangles.clear(); } } /* * Step 1 */ void Subdivision::calculateVertexDegree() { std::vector::iterator p_iter = Renderer::getInstance()->points->begin(); //Allocate space for all the vertices, zero it out for (; p_iter != Renderer::getInstance()->points->end(); p_iter++) { pointDegrees.push_back(0); } std::vector::iterator t_iter = Renderer::getInstance()->triangles->begin(); //Calculate degrees for each vertex for (; t_iter != Renderer::getInstance()->triangles->end(); t_iter++) { pointDegrees[t_iter->a1]++; pointDegrees[t_iter->a2]++; pointDegrees[t_iter->a3]++; } //Display the degree of all vertices /*for (unsigned int i = 0; i < pointDegrees.size(); i++) { std::cout << "Index: " << i << ": " << pointDegrees[i] << std::endl; }*/ } /* * Step 2 */ void Subdivision::calculateIncidentTriangles() { std::vector *triangles = Renderer::getInstance()->triangles; std::vector * points = Renderer::getInstance()->points; for (unsigned int i = 0; i < Renderer::getInstance()->triangles->size(); i++) { points->at((*triangles)[i].a1).incidentTriangles.push_back(i); points->at((*triangles)[i].a2).incidentTriangles.push_back(i); points->at((*triangles)[i].a3).incidentTriangles.push_back(i); } //Display the incident triangles /*std::vector::iterator ui_iter; for (unsigned int i = 0; i < points->size(); i++) { std::cout << "Incident Tris for Point: " << i << std::endl << " "; ui_iter = (*points)[i].incidentTriangles.begin(); for (; ui_iter != (*points)[i].incidentTriangles.end(); ui_iter++) { std::cout << *ui_iter << " "; } std::cout << "\n"; }*/ } /* * Step 3 */ void Subdivision::generateAdjacencyTable() { std::vector *triangles = Renderer::getInstance()->triangles; std::vector *points = Renderer::getInstance()->points; std::vector::iterator ui_iter; int a1,a2,a3; Adjacency tris; for (unsigned int i = 0; i < triangles->size(); i++) { a1 = (*triangles)[i].a1; a2 = (*triangles)[i].a2; a3 = (*triangles)[i].a3; //Find the adjacent tri to a1 -- a2 a3 ui_iter = points->at(a2).incidentTriangles.begin(); for ( ; ui_iter != points->at(a2).incidentTriangles.end(); ui_iter++) { if ( *ui_iter != i && (*triangles)[*ui_iter].contains(a3) ) { tris.a1 = *ui_iter; break; } } //Find the adjacent tri to a2 -- a3 a1 ui_iter = points->at(a3).incidentTriangles.begin(); for ( ; ui_iter != points->at(a3).incidentTriangles.end(); ui_iter++) { if ( *ui_iter != i && (*triangles)[*ui_iter].contains(a1) ) { tris.a2 = *ui_iter; break; } } //Find the adjacent tri to a3 -- a1 a2 ui_iter = points->at(a1).incidentTriangles.begin(); for ( ; ui_iter != points->at(a1).incidentTriangles.end(); ui_iter++) { if ( *ui_iter != i && (*triangles)[*ui_iter].contains(a2) ) { tris.a3 = *ui_iter; break; } } //Add to Adjacency Table this->adjacencies.push_back(tris); } /*std::vector::iterator adj_iter = this->adjacencies.begin(); for (int i = 0; adj_iter != this->adjacencies.end(); adj_iter++, i++) { std::cout << "Adjacency " << i << ": " << adj_iter->a1 << " " << adj_iter->a2 << " " << adj_iter->a3 << std::endl; }*/ } /* * Step 4 */ void Subdivision::applyToAdjacent(Triangle& tdest, int tdest_index, int edgeVertex1, int edgeVertex2, int ui_current) { switch (tdest.indexOf(edgeVertex1,edgeVertex2)) { case 1: labels.at(tdest_index).a1 = ui_current; break; case 2: labels.at(tdest_index).a2 = ui_current; break; case 3: labels.at(tdest_index).a3 = ui_current; break; default: assert(1 != 1); break; } } void Subdivision::generateLabels() { Adjacency a; std::vector *triangles = Renderer::getInstance()->triangles; unsigned int tri_index; std::vector::iterator adj_iter = this->adjacencies.begin(); int ui_current = 0; a.a1 = a.a2 = a.a3 = -1; //Set all to negative 1 for (; adj_iter != this->adjacencies.end(); adj_iter++) { this->labels.push_back(a); } //Assign edge numbers for (tri_index = 0; tri_index < triangles->size(); tri_index++) { if (labels.at(tri_index).a1 == -1) { //Set the opposite edge to this value labels.at(tri_index).a1 = ui_current; //get the adjacent Triangle int adjTri = adjacencies.at(tri_index).a1; Triangle &tdest = triangles->at(adjTri); Triangle &tsrc = triangles->at(tri_index); this->applyToAdjacent(tdest,adjTri,tsrc.a2,tsrc.a3,ui_current); ui_current++; } if (labels.at(tri_index).a2 == -1) { //Set the opposite edge to this value labels.at(tri_index).a2 = ui_current; //get the adjacent Triangle int adjTri = adjacencies.at(tri_index).a2; Triangle &tdest = triangles->at(adjTri); Triangle &tsrc = triangles->at(tri_index); this->applyToAdjacent(tdest,adjTri,tsrc.a1,tsrc.a3,ui_current); ui_current++; } if (labels.at(tri_index).a3 == -1) { //Set the opposite edge to this value labels.at(tri_index).a3 = ui_current; //get the adjacent Triangle int adjTri = adjacencies.at(tri_index).a3; Triangle &tdest = triangles->at(adjTri); Triangle &tsrc = triangles->at(tri_index); this->applyToAdjacent(tdest,adjTri,tsrc.a1,tsrc.a2,ui_current); ui_current++; } } /*std::vector::iterator lab_iter = this->labels.begin(); for (; lab_iter != this->labels.end(); lab_iter++) { std::cout << "Edge nums: " << lab_iter->a1 << " " << lab_iter->a2 << " " << lab_iter->a3 << std::endl; } */ } /* * Step 5 */ void Subdivision::generateNewVertices() { newPoints = new std::vector; *newPoints = *(Renderer::getInstance()->points); Point p; p.x = p.y = p.z = 0; //std::cout << (int)newPoints->size() << std::endl; int numEdges = (3*(int)Renderer::getInstance()->triangles->size()) / 2; for (int i = 0; i < numEdges; i++) { newPoints->push_back(p); } //std::cout << (int) newPoints->size() << std::endl; } void Subdivision::generateNewTriangles() { std::vector *triangles = Renderer::getInstance()->triangles; //std::vector::iterator t_iter; unsigned int tri_index; Triangle tTemp; int numVertices = (int) Renderer::getInstance()->points->size(); newTriangles = new std::vector; for (tri_index = 0; tri_index < triangles->size(); tri_index++) { Triangle ¤t = (*triangles)[tri_index]; //Generate the first triangle -> a1, a1a2, a3a1 tTemp.a1 = current.a1; tTemp.a2 = labels.at(tri_index).a3 + numVertices; tTemp.a3 = labels.at(tri_index).a2 + numVertices; newTriangles->push_back(tTemp); //Generate the second triangle -> a1a2, a2a3, a3a1 tTemp.a1 = labels.at(tri_index).a3 + numVertices; tTemp.a2 = labels.at(tri_index).a1 + numVertices; tTemp.a3 = labels.at(tri_index).a2 + numVertices; newTriangles->push_back(tTemp); //Generate the third triangle -> a1a2, a2, a2a3 tTemp.a1 = labels.at(tri_index).a3 + numVertices; tTemp.a2 = current.a2; tTemp.a3 = labels.at(tri_index).a1 + numVertices; newTriangles->push_back(tTemp); //Generate the fourth triangle -> a1a3, a2a3, a3 tTemp.a1 = labels.at(tri_index).a2 + numVertices; tTemp.a2 = labels.at(tri_index).a1 + numVertices; tTemp.a3 = current.a3; newTriangles->push_back(tTemp); } //std::cout << "new Triangles size: " << newTriangles.size() << std::endl; } /* * Step 6 */ void Subdivision::generateNewVertexCoords(char type) { if (type == 'L') { //this->splitTriangles(); this->loopSubdivide(); } else if (type == 'B') { //this->splitTriangles(); this->butterflySubdivide(); } else { this->splitTriangles(); } } Point Subdivision::pointOppositeTo(Triangle &t, int in1, int in2, std::vector *points) { switch (t.indexOf(in1,in2)) { case 1: return points->at(t.a1); case 2: return points->at(t.a2); case 3: return points->at(t.a3); default: assert(0 != 0); //Shut up compiler Point p; return p; } } Point Subdivision::farOppositePoints(Triangle &tAdj, int in1, int in2) { std::vector *points = Renderer::getInstance()->points; std::vector *triangles = Renderer::getInstance()->triangles; Point temp; unsigned int ui_num; for (int i=0; i < (int) points->at(in1).incidentTriangles.size(); i++) { if (triangles->at(points->at(in1).incidentTriangles[i]) == tAdj) { ui_num = points->at(in1).incidentTriangles[i]; break; } } switch (tAdj.indexOf(in1,in2)) { case 1: //a2a3 = adjacent edge temp = temp + (pointOppositeTo(triangles->at(adjacencies.at(ui_num).a2),tAdj.a1,tAdj.a3,points) * this->bfly_edge_far_weight); temp = temp + (pointOppositeTo(triangles->at(adjacencies.at(ui_num).a3),tAdj.a1,tAdj.a2,points) * this->bfly_edge_far_weight); break; case 2: //a1a3 = adjacent edge temp = temp + (pointOppositeTo(triangles->at(adjacencies.at(ui_num).a1),tAdj.a2,tAdj.a3,points) * this->bfly_edge_far_weight); temp = temp + (pointOppositeTo(triangles->at(adjacencies.at(ui_num).a3),tAdj.a2,tAdj.a1,points) * this->bfly_edge_far_weight); break; case 3: //a1a2 = adjacent edge temp = temp + (pointOppositeTo(triangles->at(adjacencies.at(ui_num).a1),tAdj.a2,tAdj.a3,points) * this->bfly_edge_far_weight); temp = temp + (pointOppositeTo(triangles->at(adjacencies.at(ui_num).a2),tAdj.a1,tAdj.a3,points) * this->bfly_edge_far_weight); break; default: assert(0 != 0); break; } return temp; } void Subdivision::butterflySubdivide() { std::vector *points = Renderer::getInstance()->points; std::vector *triangles = Renderer::getInstance()->triangles; //Copy the old point locations for (unsigned int p_index = 0; p_index < (unsigned int) points->size(); p_index++) { newPoints->at(p_index) = points->at(p_index); } unsigned int ui_edge = 0; //Current edge we be using for (unsigned int ui = 0; ui < labels.size(); ui++) { Adjacency &a = labels.at(ui); if (a.a1 == ui_edge) { Point Q; Triangle &t = triangles->at(ui); Triangle tAdj = triangles->at(adjacencies.at(ui).a1); //Adjacent Edges Q = points->at(t.a2) + points->at(t.a3); Q = Q * this->bfly_edge_adjacent_weight; //Opposite Edges Q = Q + (points->at(t.a1) * this->bfly_edge_opposite_weight); Q = Q + (pointOppositeTo(tAdj,t.a2,t.a3,points) * this->bfly_edge_opposite_weight); //Far Edges //a1a2 Q = Q + (pointOppositeTo(triangles->at(adjacencies.at(ui).a3),t.a1,t.a2,points) * this->bfly_edge_far_weight); //a1a3 Q = Q + (pointOppositeTo(triangles->at(adjacencies.at(ui).a2),t.a1,t.a3,points) * this->bfly_edge_far_weight); //opposite Triangle Q = Q + farOppositePoints(tAdj,t.a2,t.a3); newPoints->at(ui_edge + points->size()) = Q; ui_edge++; } if (a.a2 == ui_edge) { Point Q; Triangle &t = triangles->at(ui); Triangle tAdj = triangles->at(adjacencies.at(ui).a2); //Adjacent Edges Q = points->at(t.a1) + points->at(t.a3); Q = Q * this->bfly_edge_adjacent_weight; //Opposite Edges Q = Q + (points->at(t.a2) * this->bfly_edge_opposite_weight); Q = Q + (pointOppositeTo(tAdj,t.a1,t.a3,points) * this->bfly_edge_opposite_weight); //Far Edges //a1a2 Q = Q + (pointOppositeTo(triangles->at(adjacencies.at(ui).a3),t.a1,t.a2,points) * this->bfly_edge_far_weight); //a1a3 Q = Q + (pointOppositeTo(triangles->at(adjacencies.at(ui).a1),t.a2,t.a3,points) * this->bfly_edge_far_weight); //opposite Triangle Q = Q + farOppositePoints(tAdj,t.a1,t.a3); newPoints->at(ui_edge + points->size()) = Q; ui_edge++; } if (a.a3 == ui_edge) { Point Q; Triangle &t = triangles->at(ui); Triangle tAdj = triangles->at(adjacencies.at(ui).a3); //Adjacent Edges Q = points->at(t.a1) + points->at(t.a2); Q = Q * this->bfly_edge_adjacent_weight; //Opposite Edges Q = Q + (points->at(t.a3) * this->bfly_edge_opposite_weight); Q = Q + (pointOppositeTo(tAdj,t.a1,t.a2,points) * this->bfly_edge_opposite_weight); //Far Edges //a1a2 Q = Q + (pointOppositeTo(triangles->at(adjacencies.at(ui).a2),t.a1,t.a3,points) * this->bfly_edge_far_weight); //a1a3 Q = Q + (pointOppositeTo(triangles->at(adjacencies.at(ui).a1),t.a2,t.a3,points) * this->bfly_edge_far_weight); //opposite Triangle Q = Q + farOppositePoints(tAdj,t.a1,t.a2); newPoints->at(ui_edge + points->size()) = Q; ui_edge++; } } //this->splitTriangles(); } void Subdivision::loopSubdivide() { std::vector *points = Renderer::getInstance()->points; std::vector *triangles = Renderer::getInstance()->triangles; //Traverse all points and generate their new locations for (unsigned int p_index = 0; p_index < points->size(); p_index++) { Point &p = points->at(p_index); Point temp; for (unsigned int ui = 0; ui < p.incidentTriangles.size(); ui++) { Triangle t = triangles->at(p.incidentTriangles[ui]); temp += points->at(t.a1); temp += points->at(t.a2); temp += points->at(t.a3); //Subtract off self -- is this faster than using a bunch of if's? //Probably, since there would be at least one false if (or one true) //And that would piss off the pipeline temp = temp - p; } //All points were counted twice temp = temp / 2.; //Use point Degrees to figure out next step if (pointDegrees.at(p_index) == 3) { //std::cout << "DEGREE THREE!!!!\n\n"; temp = temp * this->d3_loop_neighbor_weight; temp += p * this->d3_loop_center_weight; } else { temp = temp * this->dn_loop_neighbor_weight(pointDegrees.at(p_index)); temp += p * this->dn_loop_center_weight; } newPoints->at(p_index) = temp; /*std::cout << "Old: "; p.printMe(); std::cout << "\nNew: "; temp.printMe(); std::cout << "\n";*/ } /* Do the calculations for edge vertex locations */ //Calculate the number of edges unsigned int ui_edge = 0; /* * TODO: REFACTOR!!!! */ for (unsigned int ui = 0; ui < labels.size(); ui++) { Adjacency &a = labels.at(ui); if (a.a1 == ui_edge) { Point Q; Triangle &t = triangles->at(ui); Triangle &tAdj = triangles->at(adjacencies.at(ui).a1); //Add the edge points Q = points->at(t.a2) + points->at(t.a3); Q = Q * this->loop_edge_adjacent_weight; //Add the opposite points Q = Q + (points->at(t.a1) * this->loop_edge_opposite_weight); switch (tAdj.indexOf(t.a2, t.a3)) { case 1: Q = Q + (points->at(tAdj.a1) * this->loop_edge_opposite_weight); break; case 2: Q = Q + (points->at(tAdj.a2) * this->loop_edge_opposite_weight); break; case 3: Q = Q + (points->at(tAdj.a3) * this->loop_edge_opposite_weight); break; default: assert(0 != 0); break; } newPoints->at(ui_edge + points->size()) = Q; ui_edge++; } if (a.a2 == ui_edge) { Point Q; Triangle &t = triangles->at(ui); Triangle &tAdj = triangles->at(adjacencies.at(ui).a2); //Add the edge points Q = points->at(t.a1) + points->at(t.a3); Q = Q * this->loop_edge_adjacent_weight; //Add the opposite points Q = Q + (points->at(t.a2) * this->loop_edge_opposite_weight); switch (tAdj.indexOf(t.a1, t.a3)) { case 1: Q = Q + (points->at(tAdj.a1) * this->loop_edge_opposite_weight); break; case 2: Q = Q + (points->at(tAdj.a2) * this->loop_edge_opposite_weight); break; case 3: Q = Q + (points->at(tAdj.a3) * this->loop_edge_opposite_weight); break; default: assert(0 != 0); break; } newPoints->at(ui_edge + points->size()) = Q; ui_edge++; } if (a.a3 == ui_edge) { Point Q; Triangle &t = triangles->at(ui); Triangle &tAdj = triangles->at(adjacencies.at(ui).a3); //Add the edge points Q = points->at(t.a1) + points->at(t.a2); Q = Q * this->loop_edge_adjacent_weight; //Add the opposite points Q = Q + (points->at(t.a3) * this->loop_edge_opposite_weight); switch (tAdj.indexOf(t.a1, t.a2)) { case 1: Q = Q + (points->at(tAdj.a1) * this->loop_edge_opposite_weight); break; case 2: Q = Q + (points->at(tAdj.a2) * this->loop_edge_opposite_weight); break; case 3: Q = Q + (points->at(tAdj.a3) * this->loop_edge_opposite_weight); break; default: assert(0 != 0); break; } newPoints->at(ui_edge + points->size()) = Q; ui_edge++; } } } void Subdivision::splitTriangles() { std::vector *triangles = Renderer::getInstance()->triangles; std::vector *points = Renderer::getInstance()->points; int numVertices = (int) Renderer::getInstance()->points->size(); Point* p; Triangle tCurr; for (int tri_index = 0; tri_index < (int)triangles->size(); tri_index++) { tCurr = triangles->at(tri_index); /*std::cout << labels.at(tri_index).a1+numVertices << std::endl; std::cout << (int) newPoints->size() << std::endl;*/ //a2a3 p = &(newPoints->at(labels.at(tri_index).a1+numVertices)); p->x = (points->at(tCurr.a2).x + points->at(tCurr.a3).x) / 2.; p->y = (points->at(tCurr.a2).y + points->at(tCurr.a3).y) / 2.; p->z = (points->at(tCurr.a2).z + points->at(tCurr.a3).z) / 2.; //a1a3 p = &(newPoints->at(labels.at(tri_index).a2+numVertices)); p->x = (points->at(tCurr.a1).x + points->at(tCurr.a3).x) / 2.; p->y = (points->at(tCurr.a1).y + points->at(tCurr.a3).y) / 2.; p->z = (points->at(tCurr.a1).z + points->at(tCurr.a3).z) / 2.; //a1a2 p = &(newPoints->at(labels.at(tri_index).a3+numVertices)); p->x = (points->at(tCurr.a2).x + points->at(tCurr.a1).x) / 2.; p->y = (points->at(tCurr.a2).y + points->at(tCurr.a1).y) / 2.; p->z = (points->at(tCurr.a2).z + points->at(tCurr.a1).z) / 2.; } }