static void generate_cube(const float width, const float height, const float depth, const unsigned int flags, SoShape * const shape, SoAction * const action) { SbVec3f varray[8]; sogenerate_generate_cube_vertices(varray, width * 0.5f, height * 0.5f, depth * 0.5f); SoPrimitiveVertex vertex; SoCubeDetail cubeDetail; vertex.setDetail(&cubeDetail); vertex.setMaterialIndex(0); shape->beginShape(action, SoShape::QUADS); int *iptr = sogenerate_cube_vindices; const SbVec3f *nptr = sogenerate_cube_normals; const SbVec2f *tptr = sogenerate_cube_texcoords; for (int i = 0; i < 6; i++) { // 6 quads vertex.setNormal(nptr[i]); if (flags & SOGEN_MATERIAL_PER_PART) vertex.setMaterialIndex(i); for (int j = 0; j < 4; j++) { vertex.setTextureCoords(tptr[j]); vertex.setPoint(varray[*iptr++]); shape->shapeVertex(&vertex); } } shape->endShape(); }
// Doc in parent void SoVRMLIndexedFaceSet::generatePrimitives(SoAction * action) { if (this->coordIndex.getNum() < 3) return; SoState * state = action->getState(); state->push(); SoVRMLVertexShape::doAction(action); Binding mbind = this->findMaterialBinding(state); Binding nbind = this->findNormalBinding(state); const SoCoordinateElement * coords; const SbVec3f * normals; const int32_t * cindices; int numindices; const int32_t * nindices; const int32_t * tindices; const int32_t * mindices; SbBool doTextures; SbBool sendNormals; SbBool normalCacheUsed; sendNormals = TRUE; // always generate normals this->getVertexData(state, coords, normals, cindices, nindices, tindices, mindices, numindices, sendNormals, normalCacheUsed); if (!sendNormals) { nbind = OVERALL; normals = NULL; nindices = NULL; } else if (normalCacheUsed && nbind == PER_VERTEX) { nbind = PER_VERTEX_INDEXED; } else if (normalCacheUsed && nbind == PER_FACE_INDEXED) { nbind = PER_FACE; } if (mbind == PER_VERTEX) { mbind = PER_VERTEX_INDEXED; mindices = cindices; } if (nbind == PER_VERTEX) { nbind = PER_VERTEX_INDEXED; nindices = cindices; } SoTextureCoordinateBundle tb(action, FALSE, FALSE); doTextures = tb.needCoordinates(); Binding tbind = NONE; if (doTextures) { if (tb.isFunction() && !tb.needIndices()) { tbind = NONE; tindices = NULL; } else { tbind = PER_VERTEX_INDEXED; if (tindices == NULL) tindices = cindices; } } SbBool convexcacheused = FALSE; if (this->useConvexCache(action, normals, nindices, normalCacheUsed)) { cindices = PRIVATE(this)->convexCache->getCoordIndices(); numindices = PRIVATE(this)->convexCache->getNumCoordIndices(); mindices = PRIVATE(this)->convexCache->getMaterialIndices(); nindices = PRIVATE(this)->convexCache->getNormalIndices(); tindices = PRIVATE(this)->convexCache->getTexIndices(); if (mbind == PER_VERTEX) mbind = PER_VERTEX_INDEXED; else if (mbind == PER_FACE) mbind = PER_FACE_INDEXED; if (nbind == PER_VERTEX) nbind = PER_VERTEX_INDEXED; else if (nbind == PER_FACE) nbind = PER_FACE_INDEXED; if (tbind != NONE) tbind = PER_VERTEX_INDEXED; convexcacheused = TRUE; } int texidx = 0; TriangleShape mode = POLYGON; TriangleShape newmode; const int32_t *viptr = cindices; const int32_t *viendptr = viptr + numindices; int32_t v1, v2, v3, v4, v5 = 0; // v5 init unnecessary, but kills a compiler warning. SoPrimitiveVertex vertex; SoPointDetail pointDetail; SoFaceDetail faceDetail; vertex.setDetail(&pointDetail); SbVec3f dummynormal(0,0,1); const SbVec3f *currnormal = &dummynormal; if (normals) currnormal = normals; vertex.setNormal(*currnormal); int matnr = 0; int normnr = 0; while (viptr + 2 < viendptr) { v1 = *viptr++; v2 = *viptr++; v3 = *viptr++; assert(v1 >= 0 && v2 >= 0 && v3 >= 0); v4 = viptr < viendptr ? *viptr++ : -1; if (v4 < 0) newmode = TRIANGLES; else { v5 = viptr < viendptr ? *viptr++ : -1; if (v5 < 0) newmode = QUADS; else newmode = POLYGON; } if (newmode != mode) { if (mode != POLYGON) this->endShape(); mode = newmode; this->beginShape(action, mode, &faceDetail); } else if (mode == POLYGON) this->beginShape(action, POLYGON, &faceDetail); // vertex 1 can't use DO_VERTEX if (mbind == PER_VERTEX || mbind == PER_FACE) { pointDetail.setMaterialIndex(matnr); vertex.setMaterialIndex(matnr++); } else if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) { pointDetail.setMaterialIndex(*mindices); vertex.setMaterialIndex(*mindices++); } if (nbind == PER_VERTEX || nbind == PER_FACE) { pointDetail.setNormalIndex(normnr); currnormal = &normals[normnr++]; vertex.setNormal(*currnormal); } else if (nbind == PER_FACE_INDEXED || nbind == PER_VERTEX_INDEXED) { pointDetail.setNormalIndex(*nindices); currnormal = &normals[*nindices++]; vertex.setNormal(*currnormal); } if (tb.isFunction()) { vertex.setTextureCoords(tb.get(coords->get3(v1), *currnormal)); if (tb.needIndices()) pointDetail.setTextureCoordIndex(tindices ? *tindices++ : texidx++); } else if (tbind != NONE) { pointDetail.setTextureCoordIndex(tindices ? *tindices : texidx); vertex.setTextureCoords(tb.get(tindices ? *tindices++ : texidx++)); } pointDetail.setCoordinateIndex(v1); vertex.setPoint(coords->get3(v1)); this->shapeVertex(&vertex); DO_VERTEX(v2); DO_VERTEX(v3); if (mode != TRIANGLES) { DO_VERTEX(v4); if (mode == POLYGON) { DO_VERTEX(v5); v1 = viptr < viendptr ? *viptr++ : -1; while (v1 >= 0) { DO_VERTEX(v1); v1 = viptr < viendptr ? *viptr++ : -1; } this->endShape(); } } faceDetail.incFaceIndex(); if (mbind == PER_VERTEX_INDEXED) { mindices++; } if (nbind == PER_VERTEX_INDEXED) { nindices++; } if (tindices) tindices++; } if (mode != POLYGON) this->endShape(); if (normalCacheUsed) { this->readUnlockNormalCache(); } if (convexcacheused) { PRIVATE(this)->readUnlockConvexCache(); } state->pop(); }
void SoCylinder::generatePrimitives(SoAction *action) // //////////////////////////////////////////////////////////////////////// { SbBool materialPerPart; int curParts, numSides, numSections, side, section; float yTop, yBot, dy; float s, ds, tTop, tBot, dt; float outerRadius, innerRadius, dRadius; SbVec2f *ringCoords; SbVec3f pt, norm; float radius, halfHeight; SbVec4f tex; SbBool genTexCoords; SoPrimitiveVertex pv; SoCylinderDetail detail; const SoTextureCoordinateElement *tce; SoMaterialBindingElement::Binding mbe = SoMaterialBindingElement::get(action->getState()); materialPerPart = (mbe == SoMaterialBindingElement::PER_PART_INDEXED || mbe == SoMaterialBindingElement::PER_PART); curParts = (parts.isIgnored() ? ALL : parts.getValue()); // Compute number of sides and sections to use to represent // cylinder, then compute ring of x,z coordinates around cylinder // and store in ringCoords. computeRing(action, numSides, numSections, ringCoords); pv.setDetail(&detail); // Determine whether we should generate our own texture coordinates switch (SoTextureCoordinateElement::getType(action->getState())) { case SoTextureCoordinateElement::EXPLICIT: genTexCoords = TRUE; break; case SoTextureCoordinateElement::FUNCTION: genTexCoords = FALSE; break; } // If we're not generating our own coordinates, we'll need the // texture coordinate element to get coords based on points/normals. if (! genTexCoords) tce = SoTextureCoordinateElement::getInstance(action->getState()); else { tex[2] = 0.0; tex[3] = 1.0; } getSize(radius, halfHeight); if (HAS_PART(curParts, SIDES)) { // Draw each section of sides as a triangle mesh, from top to bottom yTop = 1.0; dy = -2.0 / numSections; tTop = 1.0; dt = -1.0 / numSections; ds = -1.0 / numSides; for (section = 0; section < numSections; section++) { yBot = yTop + dy; tBot = tTop + dt; s = 1.0; detail.setPart(SIDES); beginShape(action, TRIANGLE_STRIP); for (side = 0; side < numSides; side++) { pt[0] = ringCoords[side][0]; pt[2] = ringCoords[side][1]; // Deal with normal norm.setValue(pt[0], 0.0, pt[2]); pv.setNormal(norm); // Point at bottom of section pt[1] = yBot; pt[0] *= radius; pt[1] *= halfHeight; pt[2] *= radius; if (genTexCoords) { tex[0] = s; tex[1] = tBot; } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); // Point at top of section pt[1] = yTop; pt[1] *= halfHeight; if (genTexCoords) { tex[0] = s; tex[1] = tTop; } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); s += ds; } // Join end of strip back to beginning side = 0; s = 0.0; pt[0] = ringCoords[side][0]; pt[2] = ringCoords[side][1]; // Deal with normal norm.setValue(pt[0], 0.0, pt[2]); pv.setNormal(norm); // Point at bottom of section pt[1] = yBot; pt[0] *= radius; pt[1] *= halfHeight; pt[2] *= radius; if (genTexCoords) { tex[0] = s; tex[1] = tBot; } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); // Point at top of section pt[1] = yTop; pt[1] *= halfHeight; if (genTexCoords) { tex[0] = s; tex[1] = tTop; } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); s += ds; endShape(); // Prepare for next section down yTop = yBot; tTop = tBot; } } // Draw top face as a series of concentric rings. The number of // rings is the same as the number of sections of the sides of the // cylinder. if (HAS_PART(curParts, TOP)) { norm.setValue(0.0, 1.0, 0.0); pt[1] = halfHeight; if (materialPerPart) pv.setMaterialIndex(1); pv.setNormal(norm); detail.setPart(TOP); // Start at the outside and work in outerRadius = 1.0; dRadius = -1.0 / numSections; for (section = numSections - 1; section >= 0; --section) { innerRadius = outerRadius + dRadius; // Innermost ring is treated as a triangle fan. This not // only gets better shading (because the center vertex is // sent), but also avoids the problem of having a polygon // with too many vertices. if (section == 0) { beginShape(action, TRIANGLE_FAN); // Center point comes first pt[0] = pt[2] = 0.0; if (genTexCoords) tex[0] = tex[1] = 0.5; else tex = tce->get(norm, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); // Send all vertices around ring. Go in reverse order // so that vertex ordering is correct for (side = numSides - 1; side >= 0; side--) { pt[0] = outerRadius * ringCoords[side][0]; pt[2] = outerRadius * ringCoords[side][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = TOP_TEX_S(pt[0]); tex[1] = TOP_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); } // Send first vertex again pt[0] = outerRadius * ringCoords[numSides - 1][0]; pt[2] = outerRadius * ringCoords[numSides - 1][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = TOP_TEX_S(pt[0]); tex[1] = TOP_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); endShape(); } // Other rings are triangle strips else { beginShape(action, TRIANGLE_STRIP); for (side = 0; side < numSides; side++) { // Send points on outer and inner rings pt[0] = outerRadius * ringCoords[side][0]; pt[2] = outerRadius * ringCoords[side][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = TOP_TEX_S(pt[0]); tex[1] = TOP_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); pt[0] = innerRadius * ringCoords[side][0]; pt[2] = innerRadius * ringCoords[side][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = TOP_TEX_S(pt[0]); tex[1] = TOP_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); } // Join end of strip back to beginning pt[0] = outerRadius * ringCoords[0][0]; pt[2] = outerRadius * ringCoords[0][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = TOP_TEX_S(pt[0]); tex[1] = TOP_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); pt[0] = innerRadius * ringCoords[0][0]; pt[2] = innerRadius * ringCoords[0][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = TOP_TEX_S(pt[0]); tex[1] = TOP_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); endShape(); // Prepare for next ring outerRadius = innerRadius; } } } // Draw bottom face the same way as the top if (HAS_PART(curParts, BOTTOM)) { norm.setValue(0.0, -1.0, 0.0); pt[1] = -halfHeight; if (materialPerPart) pv.setMaterialIndex(2); pv.setNormal(norm); detail.setPart(BOTTOM); // Start at the outside and work in outerRadius = 1.0; dRadius = -1.0 / numSections; for (section = numSections - 1; section >= 0; --section) { innerRadius = outerRadius + dRadius; // Innermost ring is drawn as a triangle fan. This not // only gets better shading (because the center vertex is // sent), but also avoids the problem of having a polygon // with too many vertices. if (section == 0) { beginShape(action, TRIANGLE_FAN); // Center point comes first pt[0] = pt[2] = 0.0; if (genTexCoords) tex[0] = tex[1] = 0.5; else tex = tce->get(norm, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); // Send all vertices around ring for (side = 0; side < numSides; side++) { pt[0] = outerRadius * ringCoords[side][0]; pt[2] = outerRadius * ringCoords[side][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = BOT_TEX_S(pt[0]); tex[1] = BOT_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); } // Send first vertex again pt[0] = outerRadius * ringCoords[0][0]; pt[2] = outerRadius * ringCoords[0][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = BOT_TEX_S(pt[0]); tex[1] = BOT_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); endShape(); } // Other rings are triangle strips else { beginShape(action, TRIANGLE_STRIP); // Go in reverse order so that vertex ordering is correct for (side = numSides - 1; side >= 0; side--) { // Send points on outer and inner rings pt[0] = outerRadius * ringCoords[side][0]; pt[2] = outerRadius * ringCoords[side][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = BOT_TEX_S(pt[0]); tex[1] = BOT_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); pt[0] = innerRadius * ringCoords[side][0]; pt[2] = innerRadius * ringCoords[side][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = BOT_TEX_S(pt[0]); tex[1] = BOT_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); } // Join end of strip back to beginning side = numSides - 1; pt[0] = outerRadius * ringCoords[side][0]; pt[2] = outerRadius * ringCoords[side][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = BOT_TEX_S(pt[0]); tex[1] = BOT_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); pt[0] = innerRadius * ringCoords[side][0]; pt[2] = innerRadius * ringCoords[side][1]; pt[0] *= radius; pt[2] *= radius; if (genTexCoords) { tex[0] = BOT_TEX_S(pt[0]); tex[1] = BOT_TEX_T(pt[2]); } else tex = tce->get(pt, norm); pv.setPoint(pt); pv.setTextureCoords(tex); shapeVertex(&pv); endShape(); // Prepare for next ring outerRadius = innerRadius; } } } }
void SoBrepFaceSet::generatePrimitives(SoAction * action) { //TODO #if 0 inherited::generatePrimitives(action); #else //This is highly experimental!!! if (this->coordIndex.getNum() < 3) return; SoState * state = action->getState(); if (this->vertexProperty.getValue()) { state->push(); this->vertexProperty.getValue()->doAction(action); } Binding mbind = this->findMaterialBinding(state); Binding nbind = this->findNormalBinding(state); const SoCoordinateElement * coords; const SbVec3f * normals; const int32_t * cindices; int numindices; const int32_t * nindices; const int32_t * tindices; const int32_t * mindices; SbBool doTextures; SbBool sendNormals; SbBool normalCacheUsed; sendNormals = TRUE; // always generate normals this->getVertexData(state, coords, normals, cindices, nindices, tindices, mindices, numindices, sendNormals, normalCacheUsed); SoTextureCoordinateBundle tb(action, FALSE, FALSE); doTextures = tb.needCoordinates(); if (!sendNormals) nbind = OVERALL; else if (normalCacheUsed && nbind == PER_VERTEX) { nbind = PER_VERTEX_INDEXED; } else if (normalCacheUsed && nbind == PER_FACE_INDEXED) { nbind = PER_FACE; } if (this->getNodeType() == SoNode::VRML1) { // For VRML1, PER_VERTEX means per vertex in shape, not PER_VERTEX // on the state. if (mbind == PER_VERTEX) { mbind = PER_VERTEX_INDEXED; mindices = cindices; } if (nbind == PER_VERTEX) { nbind = PER_VERTEX_INDEXED; nindices = cindices; } } Binding tbind = NONE; if (doTextures) { if (tb.isFunction() && !tb.needIndices()) { tbind = NONE; tindices = NULL; } // FIXME: just call inherited::areTexCoordsIndexed() instead of // the if-check? 20020110 mortene. else if (SoTextureCoordinateBindingElement::get(state) == SoTextureCoordinateBindingElement::PER_VERTEX) { tbind = PER_VERTEX; tindices = NULL; } else { tbind = PER_VERTEX_INDEXED; if (tindices == NULL) tindices = cindices; } } if (nbind == PER_VERTEX_INDEXED && nindices == NULL) { nindices = cindices; } if (mbind == PER_VERTEX_INDEXED && mindices == NULL) { mindices = cindices; } int texidx = 0; TriangleShape mode = POLYGON; TriangleShape newmode; const int32_t *viptr = cindices; const int32_t *viendptr = viptr + numindices; const int32_t *piptr = this->partIndex.getValues(0); int num_partindices = this->partIndex.getNum(); const int32_t *piendptr = piptr + num_partindices; int32_t v1, v2, v3, v4, v5 = 0, pi; // v5 init unnecessary, but kills a compiler warning. SoPrimitiveVertex vertex; SoPointDetail pointDetail; SoFaceDetail faceDetail; vertex.setDetail(&pointDetail); SbVec3f dummynormal(0,0,1); const SbVec3f *currnormal = &dummynormal; if (normals) currnormal = normals; vertex.setNormal(*currnormal); int matnr = 0; int normnr = 0; int trinr = 0; pi = piptr < piendptr ? *piptr++ : -1; while (pi == 0) { // It may happen that a part has no triangles pi = piptr < piendptr ? *piptr++ : -1; if (mbind == PER_PART) matnr++; else if (mbind == PER_PART_INDEXED) mindices++; } while (viptr + 2 < viendptr) { v1 = *viptr++; v2 = *viptr++; v3 = *viptr++; if (v1 < 0 || v2 < 0 || v3 < 0) { break; } v4 = viptr < viendptr ? *viptr++ : -1; if (v4 < 0) newmode = TRIANGLES; else { v5 = viptr < viendptr ? *viptr++ : -1; if (v5 < 0) newmode = QUADS; else newmode = POLYGON; } if (newmode != mode) { if (mode != POLYGON) this->endShape(); mode = newmode; this->beginShape(action, mode, &faceDetail); } else if (mode == POLYGON) this->beginShape(action, POLYGON, &faceDetail); // vertex 1 can't use DO_VERTEX if (mbind == PER_PART) { if (trinr == 0) { pointDetail.setMaterialIndex(matnr); vertex.setMaterialIndex(matnr++); } } else if (mbind == PER_PART_INDEXED) { if (trinr == 0) { pointDetail.setMaterialIndex(*mindices); vertex.setMaterialIndex(*mindices++); } } else if (mbind == PER_VERTEX || mbind == PER_FACE) { pointDetail.setMaterialIndex(matnr); vertex.setMaterialIndex(matnr++); } else if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) { pointDetail.setMaterialIndex(*mindices); vertex.setMaterialIndex(*mindices++); } if (nbind == PER_VERTEX || nbind == PER_FACE) { pointDetail.setNormalIndex(normnr); currnormal = &normals[normnr++]; vertex.setNormal(*currnormal); } else if (nbind == PER_FACE_INDEXED || nbind == PER_VERTEX_INDEXED) { pointDetail.setNormalIndex(*nindices); currnormal = &normals[*nindices++]; vertex.setNormal(*currnormal); } if (tb.isFunction()) { vertex.setTextureCoords(tb.get(coords->get3(v1), *currnormal)); if (tb.needIndices()) pointDetail.setTextureCoordIndex(tindices ? *tindices++ : texidx++); } else if (tbind != NONE) { pointDetail.setTextureCoordIndex(tindices ? *tindices : texidx); vertex.setTextureCoords(tb.get(tindices ? *tindices++ : texidx++)); } pointDetail.setCoordinateIndex(v1); vertex.setPoint(coords->get3(v1)); this->shapeVertex(&vertex); DO_VERTEX(v2); DO_VERTEX(v3); if (mode != TRIANGLES) { DO_VERTEX(v4); if (mode == POLYGON) { DO_VERTEX(v5); v1 = viptr < viendptr ? *viptr++ : -1; while (v1 >= 0) { DO_VERTEX(v1); v1 = viptr < viendptr ? *viptr++ : -1; } this->endShape(); } } faceDetail.incFaceIndex(); if (mbind == PER_VERTEX_INDEXED) { mindices++; } if (nbind == PER_VERTEX_INDEXED) { nindices++; } if (tindices) tindices++; trinr++; if (pi == trinr) { pi = piptr < piendptr ? *piptr++ : -1; while (pi == 0) { // It may happen that a part has no triangles pi = piptr < piendptr ? *piptr++ : -1; if (mbind == PER_PART) matnr++; else if (mbind == PER_PART_INDEXED) mindices++; } trinr = 0; } } if (mode != POLYGON) this->endShape(); if (normalCacheUsed) { this->readUnlockNormalCache(); } if (this->vertexProperty.getValue()) { state->pop(); } #endif }
static void generate_cylinder(const float radius, const float height, const int numslices, const unsigned int flags, SoShape * const shape, SoAction * const action) { int i; int slices = numslices; if (slices > 128) slices = 128; if (slices < 4) slices = 4; float h2 = height * 0.5f; SbVec3f coords[129]; SbVec3f normals[130]; SbVec2f texcoords[129]; sogenerate_generate_3d_circle(coords, slices, radius, -h2); coords[slices] = coords[0]; sogenerate_generate_3d_circle(normals, slices, 1.0f, 0.0f); normals[slices] = normals[0]; normals[slices+1] = normals[1]; int matnr = 0; SoPrimitiveVertex vertex; SoCylinderDetail sideDetail; SoCylinderDetail bottomDetail; SoCylinderDetail topDetail; sideDetail.setPart(SoCylinder::SIDES); bottomDetail.setPart(SoCylinder::BOTTOM); topDetail.setPart(SoCylinder::TOP); if (flags & SOGEN_GENERATE_SIDE) { shape->beginShape(action, SoShape::QUAD_STRIP); vertex.setDetail(&sideDetail); vertex.setMaterialIndex(matnr); i = 0; float t = 0.0; float inc = 1.0f / slices; while (i <= slices) { vertex.setTextureCoords(SbVec2f(t, 1.0f)); vertex.setNormal(normals[i]); SbVec3f c = coords[i]; vertex.setPoint(SbVec3f(c[0], h2, c[2])); shape->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(t, 0.0f)); vertex.setPoint(c); shape->shapeVertex(&vertex); i++; t += inc; } if (flags & SOGEN_MATERIAL_PER_PART) matnr++; shape->endShape(); } if (flags & (SOGEN_GENERATE_BOTTOM | SOGEN_GENERATE_TOP)) { sogenerate_generate_2d_circle(texcoords, slices, 0.5f); texcoords[slices] = texcoords[0]; } if (flags & SOGEN_GENERATE_TOP) { vertex.setMaterialIndex(matnr); vertex.setDetail(&topDetail); vertex.setNormal(SbVec3f(0.0f, 1.0f, 0.0f)); shape->beginShape(action, SoShape::TRIANGLE_FAN); for (i = 0; i < slices; i++) { vertex.setTextureCoords(SbVec2f(texcoords[i][0] + 0.5f, 1.0f - texcoords[i][1] - 0.5f)); const SbVec3f &c = coords[i]; vertex.setPoint(SbVec3f(c[0], h2, c[2])); shape->shapeVertex(&vertex); } shape->endShape(); if (flags & SOGEN_MATERIAL_PER_PART) matnr++; } if (flags & SOGEN_GENERATE_BOTTOM) { vertex.setMaterialIndex(matnr); vertex.setDetail(&bottomDetail); shape->beginShape(action, SoShape::TRIANGLE_FAN); vertex.setNormal(SbVec3f(0.0f, -1.0f, 0.0f)); for (i = slices-1; i >= 0; i--) { vertex.setTextureCoords(texcoords[i] + SbVec2f(0.5f, 0.5f)); vertex.setPoint(coords[i]); shape->shapeVertex(&vertex); } shape->endShape(); } }
static void generate_cone(const float radius, const float height, const int numslices, const unsigned int flags, SoShape * const shape, SoAction * const action) { int i; int slices = numslices; if (slices > 128) slices = 128; if (slices < 4) slices = 4; float h2 = height * 0.5f; // put coordinates on the stack SbVec3f coords[129]; SbVec3f normals[130]; SbVec2f texcoords[129]; sogenerate_generate_3d_circle(coords, slices, radius, -h2); coords[slices] = coords[0]; double a = atan(height/radius); sogenerate_generate_3d_circle(normals, slices, (float) sin(a), (float) cos(a)); normals[slices] = normals[0]; normals[slices+1] = normals[1]; int matnr = 0; SoPrimitiveVertex vertex; SoConeDetail sideDetail; SoConeDetail bottomDetail; sideDetail.setPart(SoCone::SIDES); bottomDetail.setPart(SoCone::BOTTOM); // FIXME: the texture coordinate generation for cone sides is of // sub-par quality. The textures comes out looking "skewed" and // "compressed". 20010926 mortene. if (flags & SOGEN_GENERATE_SIDE) { vertex.setDetail(&sideDetail); vertex.setMaterialIndex(matnr); shape->beginShape(action, SoShape::TRIANGLES); i = 0; float t = 1.0; float delta = 1.0f / slices; while (i < slices) { vertex.setTextureCoords(SbVec2f(t - delta*0.5f, 1.0f)); vertex.setNormal((normals[i] + normals[i+1])*0.5f); vertex.setPoint(SbVec3f(0.0f, h2, 0.0f)); shape->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(t, 0.0f)); vertex.setNormal(normals[i]); vertex.setPoint(coords[i]); shape->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(t-delta, 0.0f)); vertex.setNormal(normals[i+1]); vertex.setPoint(coords[i+1]); shape->shapeVertex(&vertex); i++; t -= delta; } if (flags & SOGEN_MATERIAL_PER_PART) matnr++; shape->endShape(); } if (flags & SOGEN_GENERATE_BOTTOM) { vertex.setDetail(&bottomDetail); vertex.setMaterialIndex(matnr); sogenerate_generate_2d_circle(texcoords, slices, 0.5f); texcoords[slices] = texcoords[0]; shape->beginShape(action, SoShape::TRIANGLE_FAN); vertex.setNormal(SbVec3f(0.0f, -1.0f, 0.0f)); for (i = slices-1; i >= 0; i--) { vertex.setTextureCoords(texcoords[i]+SbVec2f(0.5f, 0.5f)); vertex.setPoint(coords[i]); shape->shapeVertex(&vertex); } shape->endShape(); } }