void QGLBezierPatchesPrivate::subdivide(QGLBuilder *list) const { QGeometryData prim; int count = positions.size(); for (int posn = 0; (posn + 15) < count; posn += 16) { // Construct a QGLBezierPatch object from the next high-level patch. QGLBezierPatch patch; int vertex; for (int vertex = 0; vertex < 16; ++vertex) patch.points[vertex] = positions[posn + vertex]; QVector2D tex1, tex2; if (!textureCoords.isEmpty()) { tex1 = textureCoords[(posn / 16) * 2]; tex2 = textureCoords[(posn / 16) * 2 + 1]; } else { tex1 = QVector2D(0.0f, 0.0f); tex2 = QVector2D(1.0f, 1.0f); } qreal xtex = tex1.x(); qreal ytex = tex1.y(); qreal wtex = tex2.x() - xtex; qreal htex = tex2.y() - ytex; for (int corner = 0; corner < 4; ++corner) { vertex = posn + cornerOffsets[corner]; QVector3D n = patch.normal(cornerS[corner], cornerT[corner]); patch.indices[corner] = prim.count(); prim.appendVertex(patch.points[cornerOffsets[corner]]); prim.appendNormal(n); prim.appendTexCoord (QVector2D(xtex + wtex * cornerS[corner], ytex + htex * cornerT[corner])); } // Subdivide the patch and generate the final triangles. patch.recursiveSubDivide(&prim, subdivisionDepth, xtex, ytex, wtex, htex); } list->addTriangles(prim); }
qreal QGLBezierPatchesPrivate::intersection (const QRay3D &ray, bool anyIntersection, QVector2D *texCoord, int *bestPatch) const { int count = positions.size(); qreal result = qSNaN(); QVector2D tc; if (bestPatch) *bestPatch = -1; for (int posn = 0; (posn + 15) < count; posn += 16) { QGLBezierPatch patch; for (int vertex = 0; vertex < 16; ++vertex) patch.points[vertex] = positions[posn + vertex]; QVector2D tex1, tex2; if (!textureCoords.isEmpty()) { tex1 = textureCoords[(posn / 16) * 2]; tex2 = textureCoords[(posn / 16) * 2 + 1]; } else { tex1 = QVector2D(0.0f, 0.0f); tex2 = QVector2D(1.0f, 1.0f); } qreal xtex = tex1.x(); qreal ytex = tex1.y(); qreal wtex = tex2.x() - xtex; qreal htex = tex2.y() - ytex; qreal prev = result; result = patch.intersection (result, subdivisionDepth, ray, anyIntersection, xtex, ytex, wtex, htex, &tc); if (bestPatch && result != prev) *bestPatch = posn / 16; if (anyIntersection && !qIsNaN(result)) break; } if (texCoord && !qIsNaN(result)) *texCoord = tc; return result; }
void tst_QVectorArray::create2DArray() { QVector2DArray array; QVERIFY(array.isEmpty()); array.append(1.0f, 2.0f); array.append(3.0f, 4.0f); array.append(QVector2D(5.0f, 6.0f)); array.append(QPointF(7.0f, 8.0f)); array.append(QPoint(9, 10)); QCOMPARE(array.size(), 5); QVERIFY(array[0] == QVector2D(1.0f, 2.0f)); QVERIFY(array[1] == QVector2D(3.0f, 4.0f)); QVERIFY(array[2] == QVector2D(5.0f, 6.0f)); QVERIFY(array[3] == QVector2D(7.0f, 8.0f)); QVERIFY(array[4] == QVector2D(9.0f, 10.0f)); array.append(QVector2D(11.0f, 12.0f), QVector2D(13.0f, 14.0f)); array.append(QVector2D(15.0f, 16.0f), QVector2D(17.0f, 18.0f), QVector2D(19.0f, 20.0f)); array.append(QVector2D(21.0f, 22.0f), QVector2D(23.0f, 24.0f), QVector2D(25.0f, 26.0f)); for (int index = 0; index < array.size(); ++index) QVERIFY(array[index] == QVector2D(index * 2 + 1, index * 2 + 2)); QVector2DArray array2(34); QCOMPARE(array2.size(), 34); for (int index = 0; index < array2.size(); ++index) QCOMPARE(array2[index], QVector2D(0.0f, 0.0f)); QVector2DArray array3(15, QVector2D(1.0f, 2.0f)); QCOMPARE(array3.size(), 15); for (int index = 0; index < array3.size(); ++index) QCOMPARE(array3[index], QVector2D(1.0f, 2.0f)); }
void tst_QVectorArray::vector2DArray() { QVector2DArray array; QVERIFY(array.isEmpty()); array.append(1.0f, 2.0f); array.append(3.0f, 4.0f); array.append(QVector2D(5.0f, 6.0f)); array.append(QPointF(7.0f, 8.0f)); array.append(QPoint(9, 10)); QCOMPARE(array.size(), 5); QVERIFY(array[0] == QVector2D(1.0f, 2.0f)); QVERIFY(array[1] == QVector2D(3.0f, 4.0f)); QVERIFY(array[2] == QVector2D(5.0f, 6.0f)); QVERIFY(array[3] == QVector2D(7.0f, 8.0f)); QVERIFY(array[4] == QVector2D(9.0f, 10.0f)); array.append(QVector2D(11.0f, 12.0f), QVector2D(13.0f, 14.0f)); array.append(QVector2D(15.0f, 16.0f), QVector2D(17.0f, 18.0f), QVector2D(19.0f, 20.0f)); array.append(QVector2D(21.0f, 22.0f), QVector2D(23.0f, 24.0f), QVector2D(25.0f, 26.0f)); for (int index = 0; index < array.size(); ++index) QVERIFY(array[index] == QVector2D(index * 2 + 1, index * 2 + 2)); int size = array.size(); QVector2DArray result = array.scaled(1.0); // check did not change the original QCOMPARE(array.size(), size); QVERIFY(array[0] == QVector2D(1.0f, 2.0f)); QVERIFY(array[4] == QVector2D(9.0f, 10.0f)); // result should be copy - mult by 1.0 costs nothing QVERIFY(!result.isDetached()); QCOMPARE(result.size(), size); QCOMPARE(result[0], QVector2D(1.0f, 2.0f)); QCOMPARE(result[4], QVector2D(9.0f, 10.0f)); QCOMPARE(result[12], QVector2D(25.0f, 26.0f)); // now actually do a scale result = array.scaled(2.0); QCOMPARE(result.size(), size); QCOMPARE(array.size(), size); QCOMPARE(array[0], QVector2D(1.0f, 2.0f)); QCOMPARE(array[4], QVector2D(9.0f, 10.0f)); QCOMPARE(result[0], QVector2D(2.0f, 4.0f)); QCOMPARE(result[4], QVector2D(18.0f, 20.0f)); QCOMPARE(result[12], QVector2D(50.0f, 52.0f)); array.scale(1.0); QCOMPARE(array.size(), size); // should all be the same QCOMPARE(array[0], QVector2D(1.0f, 2.0f)); QCOMPARE(array[4], QVector2D(9.0f, 10.0f)); QCOMPARE(array[12], QVector2D(25.0f, 26.0f)); array.scale(2.0); QCOMPARE(array.size(), size); // size should be the same QCOMPARE(array[0], QVector2D(2.0f, 4.0f)); QCOMPARE(array[4], QVector2D(18.0f, 20.0f)); QCOMPARE(array[12], QVector2D(50.0f, 52.0f)); }
/*! Paints this GL graphics viewport onto \a painter, with the specified \a option and \a widget parameters. This override creates a QGLPainter for \a painter and passes it to paintGL(). \sa paintGL() */ void QGLGraphicsViewportItem::paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_D(QGLGraphicsViewportItem); Q_UNUSED(option); Q_UNUSED(widget); if (d->rect.isEmpty()) return; // Initialize a QGLPainter for the surface and bail out if not active. QGLPainter glpainter; if (!glpainter.begin(painter)) { qWarning("GL graphics system is not active; cannot use 3D items"); return; } // Set up the GL viewport to limit drawing to the bounds of this item. QRect viewport = painter->deviceTransform().mapRect(rect()).toRect(); QGLSubsurface surface(glpainter.currentSurface(), viewport); glpainter.pushSurface(&surface); // Set up the desired drawing options. glDisable(GL_CULL_FACE); d->setDefaults(&glpainter); if (d->backgroundColor.isValid()) { // We clear the background by drawing a triangle fan so // that the background color will blend with the underlying // screen content if it has an alpha component. glDisable(GL_DEPTH_TEST); if (d->backgroundColor.alpha() != 255) glEnable(GL_BLEND); else glDisable(GL_BLEND); QVector2DArray array; array.append(-1, -1); array.append(1, -1); array.append(1, 1); array.append(-1, 1); glpainter.projectionMatrix().setToIdentity(); glpainter.modelViewMatrix().setToIdentity(); glpainter.setStandardEffect(QGL::FlatColor); glpainter.setColor(d->backgroundColor); glpainter.setVertexAttribute(QGL::Position, array); glpainter.draw(QGL::TriangleFan, 4); } glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); // Apply the camera. glpainter.setEye(QGL::NoEye); glpainter.setCamera(d->camera); // Paint the GL contents. paintGL(&glpainter); // Disable the current drawing effect so that QGLPainter will // forcibly update the GL context the next time QGLPainter is used. glpainter.disableEffect(); // Try to restore the GL state to something paint-engine compatible. glDisable(GL_CULL_FACE); d->setDefaults(&glpainter); glDisable(GL_DEPTH_TEST); glpainter.popSurface(); }
/*! \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; }