/*! \relates QGLCubeSphere Builds the geometry for \a sphere within the specified display \a list. */ QGLBuilder& operator<<(QGLBuilder& list, const QGLCubeSphere& sphere) { /* A-----H | | | | A-----D-----E-----H-----A | | | | | | | | | | B-----C-----F-----G-----B | | | | B-----G ^ d e | c f y x--> */ qreal scale = sphere.diameter(); int depth = sphere.subdivisionDepth(); const qreal offset = 1.0f; float cube[8][3] = { { -offset, offset, -offset}, // A - 0 { -offset, -offset, -offset }, // B - 1 { -offset, -offset, offset }, // C - 2 { -offset, offset, offset }, // D - 3 { offset, offset, offset }, // E - 4 { offset, -offset, offset }, // F - 5 { offset, -offset, -offset }, // G - 6 { offset, offset, -offset }, // H - 7 }; int face[6][4] = { { 0, 1, 2, 3 }, // A-B-C-D { 3, 2, 5, 4 }, // D-C-F-E { 4, 5, 6, 7 }, // E-F-G-H { 7, 6, 1, 0 }, // H-G-B-A { 0, 3, 4, 7 }, // A-D-E-H { 2, 1, 6, 5 }, // C-B-G-F }; const float v3 = 0.0f; const float v2 = 0.333333333f; const float v1 = 0.666666666f; const float v0 = 1.0f; const float u0 = 0.0f; const float u1 = 0.25f; const float u2 = 0.5f; const float u3 = 0.75f; const float u4 = 1.0f; float tex[6][4][2] = { { {u0, v1}, {u0, v2}, {u1, v2}, {u1, v1} }, // A-B-C-D { {u1, v1}, {u1, v2}, {u2, v2}, {u2, v1} }, // D-C-F-E { {u2, v1}, {u2, v2}, {u3, v2}, {u3, v1} }, // E-F-G-H { {u3, v1}, {u3, v2}, {u4, v2}, {u4, v1} }, // H-G-B-A { {u1, v0}, {u1, v1}, {u2, v1}, {u2, v0} }, // A-D-E-H { {u1, v2}, {u1, v3}, {u2, v3}, {u2, v2} }, // C-B-G-F }; // Generate the initial vertex list from a plain cube. QVector3DArray vertices; QVector3DArray normals; QVector2DArray texCoords; for (int ix = 0; ix < 6; ++ix) { QVector3D n0(cube[face[ix][0]][0], cube[face[ix][0]][1], cube[face[ix][0]][2]); QVector3D n1(cube[face[ix][1]][0], cube[face[ix][1]][1], cube[face[ix][1]][2]); QVector3D n2(cube[face[ix][2]][0], cube[face[ix][2]][1], cube[face[ix][2]][2]); QVector3D n3(cube[face[ix][3]][0], cube[face[ix][3]][1], cube[face[ix][3]][2]); QVector2D t0(tex[ix][0][0], tex[ix][0][1]); QVector2D t1(tex[ix][1][0], tex[ix][1][1]); QVector2D t2(tex[ix][2][0], tex[ix][2][1]); QVector2D t3(tex[ix][3][0], tex[ix][3][1]); n0 = n0.normalized(); n1 = n1.normalized(); n2 = n2.normalized(); n3 = n3.normalized(); QVector3D v0 = n0 * scale / 2.0f; QVector3D v1 = n1 * scale / 2.0f; QVector3D v2 = n2 * scale / 2.0f; QVector3D v3 = n3 * scale / 2.0f; vertices.append(v0, v1, v2, v3); normals.append(n0, n1, n2, n3); texCoords.append(t0, t1, t2, t3); } // Subdivide the cube. while (depth-- > 1) { QVector3DArray newVertices; QVector3DArray newNormals; QVector2DArray newTexCoords; int count = vertices.count(); for (int i = 0; i < count; i+= 4) { QVector3D v0 = vertices.at(i); QVector3D v1 = vertices.at(i+1); QVector3D v2 = vertices.at(i+2); QVector3D v3 = vertices.at(i+3); QVector3D n0 = normals.at(i); QVector3D n1 = normals.at(i+1); QVector3D n2 = normals.at(i+2); QVector3D n3 = normals.at(i+3); QVector2D t0 = texCoords.at(i); QVector2D t1 = texCoords.at(i+1); QVector2D t2 = texCoords.at(i+2); QVector2D t3 = texCoords.at(i+3); QVector3D n01 = (v0 + v1).normalized(); QVector3D n12 = (v1 + v2).normalized(); QVector3D n23 = (v2 + v3).normalized(); QVector3D n30 = (v3 + v0).normalized(); QVector3D nc = (v0 + v1 + v2 + v3).normalized(); QVector3D v01 = n01 * scale / 2.0f; QVector3D v12 = n12 * scale / 2.0f; QVector3D v23 = n23 * scale / 2.0f; QVector3D v30 = n30 * scale / 2.0f; QVector3D vc = nc * scale / 2.0f; QVector2D t01 = (t0 + t1) / 2; QVector2D t12 = (t1 + t2) / 2; QVector2D t23 = (t2 + t3) / 2; QVector2D t30 = (t3 + t0) / 2; QVector2D tc = (t2 + t0) / 2; newVertices.append(v0, v01, vc, v30); newNormals.append(n0, n01, nc, n30); newTexCoords.append(t0, t01, tc, t30); newVertices.append(v01, v1, v12, vc); newNormals.append(n01, n1, n12, nc); newTexCoords.append(t01, t1, t12, tc); newVertices.append(vc, v12, v2, v23); newNormals.append(nc, n12, n2, n23); newTexCoords.append(tc, t12, t2, t23); newVertices.append(v30, vc, v23, v3); newNormals.append(n30, nc, n23, n3); newTexCoords.append(t30, tc, t23, t3); } vertices = newVertices; normals = newNormals; texCoords = newTexCoords; } // Add the final vertices to the display list. QGeometryData prim; prim.appendVertexArray(vertices); prim.appendNormalArray(normals); prim.appendTexCoordArray(texCoords); list.addTriangles(prim); return list; }
/*! \relates QGLIcoSphere Builds the geometry for \a sphere within the specified display \a list. */ QGLBuilder& operator<<(QGLBuilder& list, const QGLIcoSphere& sphere) { qreal scale = sphere.diameter(); int depth = sphere.subdivisionDepth(); qreal tiny= 1.0f; qreal large = phi*tiny; float ico[12][3] = { { 0.0f, tiny, large }, // A - 0 { 0.0f, tiny, -large }, // B - 1 { 0.0f, -tiny, large }, // C - 2 { 0.0f, -tiny, -large }, // D - 3 { tiny, large, 0.0f }, // E - 4 { tiny, -large, 0.0f }, // F - 5 { -tiny, large, 0.0f }, // G - 6 { -tiny, -large, 0.0f }, // H - 7 { large, 0.0f, tiny}, // I - 8 { large, 0.0f, -tiny}, // J - 9 { -large, 0.0f, tiny}, // K - 10 { -large, 0.0f, -tiny} // L - 11 }; int face[20][3] = { { 4, 0, 8 }, // E-A-I { 6, 0, 4 }, // G-A-E { 6, 10, 0 }, // G-K-A { 11, 10, 6 }, // L-K-G { 0, 2, 8 }, // A-C-I { 10, 2, 0 }, // K-C-A { 10, 7, 2 }, // K-H-C { 11, 7, 10 }, // L-H-K { 2, 5, 8 }, // C-F-I { 7, 5, 2 }, // H-F-C { 7, 3, 5 }, // H-D-F { 11, 3, 7 }, // L-D-H { 5, 9, 8 }, // F-J-I { 3, 9, 5 }, // D-J-F { 3, 1, 9 }, // D-B-J { 11, 1, 3 }, // L-B-D { 9, 4, 8 }, // J-E-I { 1, 4, 9 }, // B-E-J { 1, 6, 4 }, // B-G-E { 11, 6, 1 } // L-G-B }; const float u0 = 0.0f; const float u1 = 0.173205081f; const float u2 = 0.346410162f; const float u3 = 0.519615242f; const float u4 = 0.692820323f; const float u5 = 0.866025402f; const float v9 = 0.0f; const float v8 = 0.111111111f; const float v7 = 0.222222222f; const float v6 = 0.333333333f; const float v5 = 0.444444444f; const float v4 = 0.555555555f; const float v3 = 0.666666666f; const float v2 = 0.777777777f; const float v1 = 0.888888888f; const float v0 = 1.0f; float tex[20][3][2] = { { { u0, v1 }, { u1, v2 }, { u1, v0 } }, // E-A-I { { u0, v3 }, { u1, v2 }, { u0, v1 } }, // G-A-E { { u0, v3 }, { u1, v4 }, { u1, v2 } }, // G-K-A { { u0, v5 }, { u1, v4 }, { u0, v3 } }, // L-K-G { { u1, v2 }, { u2, v3 }, { u2, v1 } }, // A-C-I { { u1, v4 }, { u2, v3 }, { u1, v2 } }, // K-C-A { { u1, v4 }, { u2, v5 }, { u2, v3 } }, // K-H-C { { u1, v6 }, { u2, v5 }, { u1, v4 } }, // L-H-K { { u2, v3 }, { u3, v4 }, { u3, v2 } }, // C-F-I { { u2, v5 }, { u3, v4 }, { u2, v3 } }, // H-F-C { { u2, v5 }, { u3, v6 }, { u3, v4 } }, // H-D-F { { u2, v7 }, { u3, v6 }, { u2, v5 } }, // L-D-H { { u3, v4 }, { u4, v5 }, { u4, v3 } }, // F-J-I { { u3, v6 }, { u4, v5 }, { u3, v4 } }, // D-J-F { { u3, v6 }, { u4, v7 }, { u4, v5 } }, // D-B-J { { u3, v8 }, { u4, v7 }, { u3, v6 } }, // L-B-D { { u4, v5 }, { u5, v6 }, { u5, v4 } }, // J-E-I { { u4, v7 }, { u5, v6 }, { u4, v5 } }, // B-E-J { { u4, v7 }, { u5, v8 }, { u5, v6 } }, // B-G-E { { u4, v9 }, { u5, v8 }, { u4, v7 } } // L-G-B }; // Generate the initial vertex list from a plain icosahedron. QVector3DArray vertices; QVector3DArray normals; QVector2DArray texCoords; for (int ix = 0; ix < 20; ++ix) { QVector3D n0(ico[face[ix][0]][0], ico[face[ix][0]][1], ico[face[ix][0]][2]); QVector3D n1(ico[face[ix][1]][0], ico[face[ix][1]][1], ico[face[ix][1]][2]); QVector3D n2(ico[face[ix][2]][0], ico[face[ix][2]][1], ico[face[ix][2]][2]); QVector2D t0(tex[ix][0][0], tex[ix][0][1]); QVector2D t1(tex[ix][1][0], tex[ix][1][1]); QVector2D t2(tex[ix][2][0], tex[ix][2][1]); n0 = n0.normalized(); n1 = n1.normalized(); n2 = n2.normalized(); QVector3D v0 = n0 * scale / 2.0f; QVector3D v1 = n1 * scale / 2.0f; QVector3D v2 = n2 * scale / 2.0f; vertices.append(v0, v1, v2); normals.append(n0, n1, n2); texCoords.append(t0, t1, t2); } // Subdivide the icosahedron. while (depth-- > 1) { QVector3DArray newVertices; QVector3DArray newNormals; QVector2DArray newTexCoords; int count = vertices.count(); for (int i = 0; i < count; i+= 3) { QVector3D v0 = vertices.at(i); QVector3D v1 = vertices.at(i+1); QVector3D v2 = vertices.at(i+2); QVector3D n0 = normals.at(i); QVector3D n1 = normals.at(i+1); QVector3D n2 = normals.at(i+2); QVector2D t0 = texCoords.at(i); QVector2D t1 = texCoords.at(i+1); QVector2D t2 = texCoords.at(i+2); QVector3D n01 = (v0 + v1).normalized(); QVector3D n12 = (v1 + v2).normalized(); QVector3D n20 = (v2 + v0).normalized(); QVector3D v01 = n01 * scale / 2.0f; QVector3D v12 = n12 * scale / 2.0f; QVector3D v20 = n20 * scale / 2.0f; QVector2D t01 = (t0 + t1) / 2; QVector2D t12 = (t1 + t2) / 2; QVector2D t20 = (t2 + t0) / 2; newVertices.append(v0, v01, v20); newNormals.append(n0, n01, n20); newTexCoords.append(t0, t01, t20); newVertices.append(v01, v1, v12); newNormals.append(n01, n1, n12); newTexCoords.append(t01, t1, t12); newVertices.append(v01, v12, v20); newNormals.append(n01, n12, n20); newTexCoords.append(t01, t12, t20); newVertices.append(v20, v12, v2); newNormals.append(n20, n12, n2); newTexCoords.append(t20, t12, t2); } vertices = newVertices; normals = newNormals; texCoords = newTexCoords; } // Add the final vertices to the builder. QGeometryData prim; prim.appendVertexArray(vertices); prim.appendNormalArray(normals); prim.appendTexCoordArray(texCoords); list.addTriangles(prim); return list; }