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(); }
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 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(); }