void SoRing::generatePrimitives(SoAction* action) { SoPrimitiveVertex pv; int nbSlices = (int)((float)NbTrianglesPerRing*sweepAngle.getValue()/360.F); if ( nbSlices < 3 ) nbSlices = 3; float angleInc = (sweepAngle.getValue())*M_PI/180.F/float(nbSlices); float R1 = innerRadius.getValue(); float R2 = outerRadius.getValue(); float radiiRatio = R1/R2; float Xc, Yc; center.getValue().getValue(Xc,Yc); beginShape(action, SoShape::TRIANGLE_STRIP); float angle = sweepAngle.getValue()*M_PI/180.F; // point at outer radius pv.setPoint(SbVec3f(R2*cos(angle)+Xc,R2*sin(angle)+Yc,0)); pv.setNormal(normal); pv.setTextureCoords(SbVec4f(0.5f*(1+cos(angle)), 0.5f*(1+sin(angle)), 0, 1)); shapeVertex(&pv); // point at inner radius pv.setPoint(SbVec3f(R1*cos(angle)+Xc,R1*sin(angle)+Yc,0)); pv.setNormal(normal); pv.setTextureCoords(SbVec4f(0.5f*(1+radiiRatio*cos(angle)), 0.5f*(1+radiiRatio*sin(angle)), 0, 1)); shapeVertex(&pv); for ( int i = 0; i < nbSlices; i++ ) { angle -= angleInc; // outer radius pv.setPoint(SbVec3f((float)(R2*cos(angle))+Xc,(float)(R2*sin(angle))+Yc,0)); pv.setNormal(normal); pv.setTextureCoords(SbVec4f(0.5f*(1+cos(angle)), 0.5f*(1+sin(angle)), 0, 1)); shapeVertex(&pv); // inner radius pv.setPoint(SbVec3f((float)(R1*cos(angle))+Xc,(float)(R1*sin(angle)+Yc),0)); pv.setNormal(normal); pv.setTextureCoords(SbVec4f(0.5f*(1+radiiRatio*cos(angle)), 0.5f*(1+radiiRatio*sin(angle)), 0, 1)); shapeVertex(&pv); } endShape(); }
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(); }
void SoWidgetShape::generatePrimitives(SoAction *action) { if (this->image.isNull()) return; SoState *state = action->getState(); state->push(); SbVec2s size; SbVec3f v0, v1, v2, v3; this->getQuad(action->getState(), v0, v1, v2, v3); SbVec3f n = (v1-v0).cross(v2-v0); n.normalize(); this->beginShape(action, SoShape::QUADS); SoPrimitiveVertex vertex; vertex.setNormal(n); vertex.setTextureCoords(SbVec2f(0,0)); vertex.setPoint(v0); this->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(1,0)); vertex.setPoint(v1); this->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(1,1)); vertex.setPoint(v2); this->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(0,1)); vertex.setPoint(v3); this->shapeVertex(&vertex); this->endShape(); state->pop(); }
// 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 }
void ShapeParabolicRectangle::generatePrimitives(SoAction *action) { SoPrimitiveVertex pv; SoState *state = action->getState(); SbBool useTexFunc = ( SoTextureCoordinateElement::getType(state) == SoTextureCoordinateElement::FUNCTION ); const SoTextureCoordinateElement* tce = 0; if ( useTexFunc ) tce = SoTextureCoordinateElement::getInstance(state); SbVec3f point; const int rows = 12; // Number of points per row const int columns = 12; // Number of points per column const int totalPoints = (rows)*(columns); // Total points in the grid float vertex[totalPoints][6]; int h = 0; double ui = 0; double vj = 0; for (int i = 0; i < rows; ++i ) { ui =( 1.0 /(double)(rows-1) ) * i; for ( int j = 0 ; j < columns ; ++j ) { vj = ( 1.0 /(double)(columns-1) ) * j; Point3D point = GetPoint3D(ui, vj); NormalVector normal; if( activeSide.getValue() == 0 ) normal = -GetNormal(ui, vj); else normal = GetNormal(ui, vj); vertex[h][0] = point.x; vertex[h][1] = point.y; vertex[h][2] = point.z; vertex[h][3] = normal.x; vertex[h][4] = normal.y; vertex[h][5] = normal.z; pv.setPoint( vertex[h][0], vertex[h][1], vertex[h][2] ); h++; //Increase h to the next point. } } float u = 1; float v = 1; beginShape(action, QUADS ); for( int irow = 0; irow < (rows-1); ++irow ) { for( int icolumn = 0; icolumn < (columns-1); ++icolumn ) { int index0 = irow*columns + icolumn; SbVec3f point0( vertex[index0][0], vertex[index0][1], vertex[index0][2] ); SbVec3f normal0(vertex[index0][3], vertex[index0][4], vertex[index0][5] ); SbVec4f texCoord0 = useTexFunc ? tce->get(point0, normal0): SbVec4f( u,v, 0.0, 1.0 ); pv.setPoint(point0); pv.setNormal(normal0); pv.setTextureCoords(texCoord0); shapeVertex(&pv); int index1 = index0 + 1; SbVec3f point1( vertex[index1][0], vertex[index1][1], vertex[index1][2] ); SbVec3f normal1(vertex[index1][3], vertex[index1][4], vertex[index1][5] ); SbVec4f texCoord1 = useTexFunc ? tce->get(point1, normal1): SbVec4f( u,v, 0.0, 1.0 ); pv.setPoint(point1); pv.setNormal(normal1); pv.setTextureCoords(texCoord1); shapeVertex(&pv); int index3 = index0 + columns; int index2 = index3 + 1; SbVec3f point2( vertex[index2][0], vertex[index2][1], vertex[index2][2] ); SbVec3f normal2(vertex[index2][3], vertex[index2][4], vertex[index2][5] ); SbVec4f texCoord2 = useTexFunc ? tce->get(point2, normal2): SbVec4f( u,v, 0.0, 1.0 ); pv.setPoint(point2); pv.setNormal(normal2); pv.setTextureCoords(texCoord2); shapeVertex(&pv); SbVec3f point3( vertex[index3][0], vertex[index3][1], vertex[index3][2] ); SbVec3f normal3(vertex[index3][3], vertex[index3][4], vertex[index3][5] ); SbVec4f texCoord3 = useTexFunc ? tce->get(point3, normal3): SbVec4f( u,v, 0.0, 1.0 ); pv.setPoint(point3); pv.setNormal(normal3); pv.setTextureCoords(texCoord3); shapeVertex(&pv); } } endShape(); }
static void generate_sphere(const float radius, const int numstacks, const int numslices, SoShape * const shape, SoAction * const action) { int stacks = numstacks; int slices = numslices; if (stacks < 3) stacks = 3; if (slices < 4) slices = 4; if (slices > 128) slices = 128; // used to cache last stack's data SbVec3f coords[129]; SbVec3f normals[129]; float S[129]; int i, j; float rho; float drho; float theta; float dtheta; float tc, ts; SbVec3f tmp; drho = float(M_PI) / (float) (stacks-1); dtheta = 2.0f * float(M_PI) / (float) slices; float currs = 0.0f; float incs = 1.0f / (float)slices; rho = drho; theta = 0.0f; tc = (float) cos(rho); ts = - (float) sin(rho); tmp.setValue(0.0f, tc, ts); normals[0] = tmp; tmp *= radius; coords[0] = tmp; S[0] = currs; float dT = 1.0f / (float) (stacks-1); float T = 1.0f - dT; SoPrimitiveVertex vertex; shape->beginShape(action, SoShape::TRIANGLES); for (j = 1; j <= slices; j++) { vertex.setNormal(SbVec3f(0.0f, 1.0f, 0.0f)); vertex.setTextureCoords(SbVec2f(currs + 0.5f * incs, 1.0f)); vertex.setPoint(SbVec3f(0.0f, radius, 0.0f)); shape->shapeVertex(&vertex); vertex.setNormal(normals[j-1]); vertex.setTextureCoords(SbVec2f(currs, T)); vertex.setPoint(coords[j-1]); shape->shapeVertex(&vertex); currs += incs; theta += dtheta; S[j] = currs; tmp.setValue(float(sin(theta))*ts, tc, float(cos(theta))*ts); normals[j] = tmp; tmp *= radius; coords[j] = tmp; vertex.setNormal(normals[j]); vertex.setTextureCoords(SbVec2f(currs, T)); vertex.setPoint(coords[j]); shape->shapeVertex(&vertex); } shape->endShape(); rho += drho; for (i = 2; i < stacks-1; i++) { tc = (float)cos(rho); ts = - (float) sin(rho); shape->beginShape(action, SoShape::QUAD_STRIP); theta = 0.0f; for (j = 0; j <= slices; j++) { vertex.setTextureCoords(SbVec2f(S[j], T)); vertex.setNormal(normals[j]); vertex.setPoint(coords[j]); shape->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(S[j], T-dT)); tmp.setValue(float(sin(theta))*ts, tc, float(cos(theta))*ts); normals[j] = tmp; vertex.setNormal(tmp); tmp *= radius; coords[j] = tmp; theta += dtheta; vertex.setPoint(tmp); shape->shapeVertex(&vertex); } shape->endShape(); rho += drho; T -= dT; } shape->beginShape(action, SoShape::TRIANGLES); for (j = 0; j < slices; j++) { vertex.setTextureCoords(SbVec2f(S[j], T)); vertex.setNormal(normals[j]); vertex.setPoint(coords[j]); shape->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(S[j]+incs*0.5f, 0.0f)); vertex.setNormal(SbVec3f(0.0f, -1.0f, 0.0f)); vertex.setPoint(SbVec3f(0.0f, -radius, 0.0f)); shape->shapeVertex(&vertex); vertex.setTextureCoords(SbVec2f(S[j+1], T)); vertex.setNormal(normals[j+1]); vertex.setPoint(coords[j+1]); shape->shapeVertex(&vertex); } shape->endShape(); }
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(); } }