Exemplo n.º 1
0
void
SoCylinder::computeBBox(SoAction *, SbBox3f &box, SbVec3f &center)
//
////////////////////////////////////////////////////////////////////////
{
    int		curParts = (parts.isIgnored() ? ALL : parts.getValue());

    if (curParts == 0)		// No parts at all!
	box.setBounds(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);

    else {
	float	r, h;
	SbVec3f	min, max;

	getSize(r, h);

	if (HAS_PART(curParts, SIDES | TOP))
	    max.setValue( r,  h,  r);
	else
	    max.setValue( r, -h,  r);

	if (HAS_PART(curParts, SIDES | BOTTOM))
	    min.setValue(-r, -h, -r);
	else
	    min.setValue(-r,  h, -r);

	box.setBounds(min, max);
    }

    center.setValue(0.0, 0.0, 0.0);
}
Exemplo n.º 2
0
/*!
  Turns on a part of the arrow.
*/
void
SoArrow::addPart(Part part)
{
  arrowHeads.setValue(arrowHeads.getValue() | part);

  if (HAS_PART(arrowHeads.getValue(), SoArrow::BEGIN)) {
    calEngine->c.setValue(1);
    beginSw->whichChild.setValue(SO_SWITCH_ALL);
  }
  else {
    calEngine->c.setValue(0);
    beginSw->whichChild.setValue(SO_SWITCH_NONE);
  }

  if (HAS_PART(arrowHeads.getValue(), SoArrow::END)) {
    calEngine->d.setValue(1);
    endSw->whichChild.setValue(SO_SWITCH_ALL);
  }
  else {
    calEngine->d.setValue(0);
    endSw->whichChild.setValue(SO_SWITCH_NONE);
  }

}
Exemplo n.º 3
0
void
SoCylinder::GLRenderGeneric(SoGLRenderAction *action,
			    SbBool sendNormals, SbBool doTextures)
//
////////////////////////////////////////////////////////////////////////
{
    SbVec3f scale, tmp;
    getSize(scale[0], scale[1]);
    scale[2] = scale[0];

    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;
    SoMaterialBundle	mb(action);

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

    // Make sure first material is sent if necessary
    mb.sendFirst();

    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;

	    glBegin(GL_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]);
		if (sendNormals)
		    glNormal3fv(norm.getValue());

		// Point at bottom of section
		pt[1] = yBot;
		if (doTextures)
		    glTexCoord2f(s, tBot);
		glVertex3fv(SCALE(pt).getValue());

		// Point at top of section
		pt[1] = yTop;
		if (doTextures)
		    glTexCoord2f(s, tTop);
		glVertex3fv(SCALE(pt).getValue());
		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]);
	    if (sendNormals)
		glNormal3fv(norm.getValue());

	    // Point at bottom of section
	    pt[1] = yBot;
	    if (doTextures)
		glTexCoord2f(s, tBot);
	    glVertex3fv(SCALE(pt).getValue());

	    // Point at top of section
	    pt[1] = yTop;
	    if (doTextures)
		glTexCoord2f(s, tTop);
	    glVertex3fv(SCALE(pt).getValue());
	    s += ds;

	    glEnd();

	    // 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] = 1.0;

	if (materialPerPart)
	    mb.send(1, FALSE);
	if (sendNormals)
	    glNormal3fv(norm.getValue());

	// 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) {
		glBegin(GL_TRIANGLE_FAN);

		// Center point comes first
		pt[0] = pt[2] = 0.0;
		if (doTextures)
		    glTexCoord2f(0.5, 0.5);
		glVertex3fv(SCALE(pt).getValue());

		// 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];
		    if (doTextures)
			glTexCoord2f(TOP_TEX_S(pt[0]), TOP_TEX_T(pt[2]));
		    glVertex3fv(SCALE(pt).getValue());
		}
		// Send first vertex again
		pt[0] = outerRadius * ringCoords[numSides - 1][0];
		pt[2] = outerRadius * ringCoords[numSides - 1][1];
		if (doTextures)
		    glTexCoord2f(TOP_TEX_S(pt[0]), TOP_TEX_T(pt[2]));
		glVertex3fv(SCALE(pt).getValue());

		glEnd();
	    }

	    // Other rings are triangle strips
	    else {
		glBegin(GL_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];
		    if (doTextures)
			glTexCoord2f(TOP_TEX_S(pt[0]), TOP_TEX_T(pt[2]));
		    glVertex3fv(SCALE(pt).getValue());
		    pt[0] = innerRadius * ringCoords[side][0];
		    pt[2] = innerRadius * ringCoords[side][1];
		    if (doTextures)
			glTexCoord2f(TOP_TEX_S(pt[0]), TOP_TEX_T(pt[2]));
		    glVertex3fv(SCALE(pt).getValue());
		}

		// Join end of strip back to beginning
		pt[0] = outerRadius * ringCoords[0][0];
		pt[2] = outerRadius * ringCoords[0][1];
		if (doTextures)
		    glTexCoord2f(TOP_TEX_S(pt[0]), TOP_TEX_T(pt[2]));
		glVertex3fv(SCALE(pt).getValue());
		pt[0] = innerRadius * ringCoords[0][0];
		pt[2] = innerRadius * ringCoords[0][1];
		if (doTextures)
		    glTexCoord2f(TOP_TEX_S(pt[0]), TOP_TEX_T(pt[2]));
		glVertex3fv(SCALE(pt).getValue());

		glEnd();

		// 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] = -1.0;

	if (materialPerPart)
	    mb.send(2, FALSE);
	if (sendNormals)
	    glNormal3fv(norm.getValue());

	// 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) {
		glBegin(GL_TRIANGLE_FAN);

		// Center point comes first
		pt[0] = pt[2] = 0.0;
		if (doTextures)
		    glTexCoord2f(0.5, 0.5);
		glVertex3fv(SCALE(pt).getValue());

		// Send all vertices around ring
		for (side = 0; side < numSides; side++) {
		    pt[0] = outerRadius * ringCoords[side][0];
		    pt[2] = outerRadius * ringCoords[side][1];
		    if (doTextures)
			glTexCoord2f(BOT_TEX_S(pt[0]), BOT_TEX_T(pt[2]));
		    glVertex3fv(SCALE(pt).getValue());
		}
		// Send first vertex again
		pt[0] = outerRadius * ringCoords[0][0];
		pt[2] = outerRadius * ringCoords[0][1];
		if (doTextures)
		    glTexCoord2f(BOT_TEX_S(pt[0]), BOT_TEX_T(pt[2]));
		glVertex3fv(SCALE(pt).getValue());

		glEnd();
	    }

	    // Other rings are triangle strips
	    else {
		glBegin(GL_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];
		    if (doTextures)
			glTexCoord2f(BOT_TEX_S(pt[0]), BOT_TEX_T(pt[2]));
		    glVertex3fv(SCALE(pt).getValue());
		    pt[0] = innerRadius * ringCoords[side][0];
		    pt[2] = innerRadius * ringCoords[side][1];
		    if (doTextures)
			glTexCoord2f(BOT_TEX_S(pt[0]), BOT_TEX_T(pt[2]));
		    glVertex3fv(SCALE(pt).getValue());
		}

		// Join end of strip back to beginning
		side = numSides - 1;
		pt[0] = outerRadius * ringCoords[side][0];
		pt[2] = outerRadius * ringCoords[side][1];
		if (doTextures)
		    glTexCoord2f(BOT_TEX_S(pt[0]), BOT_TEX_T(pt[2]));
		glVertex3fv(SCALE(pt).getValue());
		pt[0] = innerRadius * ringCoords[side][0];
		pt[2] = innerRadius * ringCoords[side][1];
		if (doTextures)
		    glTexCoord2f(BOT_TEX_S(pt[0]), BOT_TEX_T(pt[2]));
		glVertex3fv(SCALE(pt).getValue());

		glEnd();

		// Prepare for next ring
		outerRadius = innerRadius;
	    }
	}
    }
}
Exemplo n.º 4
0
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;
	    }
	}
    }
}
Exemplo n.º 5
0
void
SoCylinder::rayPick(SoRayPickAction *action)
//
////////////////////////////////////////////////////////////////////////
{
    // First see if the object is pickable
    if (! shouldRayPick(action))
	return;

    int			curParts =(parts.isIgnored() ? ALL : parts.getValue());
    SbLine		pickLine;
    float		radius, halfHeight;
    SbVec3f		enterPoint, exitPoint, normal;
    SbVec4f		texCoord;
    SoPickedPoint	*pp;
    SoCylinderDetail	*detail;
    SbBool		materialPerPart;
    int			numHits = 0;

    // Compute the picking ray in our current object space
    computeObjectSpaceRay(action);

    // Get size of this cylinder
    getSize(radius, halfHeight);

    // Construct an infinite cylinder to test sides for intersection
    SbCylinder	infiniteCyl;
    infiniteCyl.setRadius(radius);

    SoMaterialBindingElement::Binding mbe =
	SoMaterialBindingElement::get(action->getState());
    materialPerPart =
	(mbe == SoMaterialBindingElement::PER_PART_INDEXED ||
	 mbe == SoMaterialBindingElement::PER_PART);

    // See if the line intersects the cylinder
    if (HAS_PART(curParts, SIDES) &&
	infiniteCyl.intersect(action->getLine(), enterPoint, exitPoint)) {

	// See if the enter point is within the real cylinder and is
	// between the near and far clipping planes.
	if (enterPoint[1] <= halfHeight && enterPoint[1] >= -halfHeight) {

	    numHits++;

	    if (action->isBetweenPlanes(enterPoint) &&
		(pp = action->addIntersection(enterPoint)) != NULL) {

		// The normal at the point is the same as the point but
		// with a 0 y coordinate
		normal.setValue(enterPoint[0], 0.0, enterPoint[2]);
		normal.normalize();
		pp->setObjectNormal(normal);

		texCoord.setValue(atan2f(enterPoint[0], enterPoint[2])
				  * (1.0 / (2.0 * M_PI)) + 0.5,
				  (enterPoint[1] + halfHeight) /
				  (2.0 * halfHeight),
				  0.0, 1.0);
		pp->setObjectTextureCoords(texCoord);

		detail = new SoCylinderDetail();
		detail->setPart(SIDES);
		pp->setDetail(detail, this);
	    }
	}

	// Do same for exit point
	if (exitPoint[1] <= halfHeight && exitPoint[1] >= -halfHeight) {
	    numHits++;

	    if (action->isBetweenPlanes(exitPoint) &&
		(pp = action->addIntersection(exitPoint)) != NULL) {
		normal.setValue(exitPoint[0], 0.0, exitPoint[2]);
		normal.normalize();
		pp->setObjectNormal(normal);
		texCoord.setValue(atan2f(exitPoint[0], exitPoint[2])
				  * (1.0 / (2.0 * M_PI)) + 0.5,
				  (exitPoint[1] + halfHeight) /
				  (2.0 * halfHeight),
				  0.0, 1.0);
		pp->setObjectTextureCoords(texCoord);
		detail = new SoCylinderDetail();
		detail->setPart(SIDES);
		pp->setDetail(detail, this);
	    }
	}
    }

    // If we haven't hit the cylinder twice already, check for an
    // intersection with the top face
    if (numHits < 2 && HAS_PART(curParts, TOP)) {
	SbVec3f	norm(0.0, 1.0, 0.0);

	// Construct a plane containing the top face
	SbPlane	topFacePlane(norm, halfHeight);

	// See if the ray hits this plane
	if (topFacePlane.intersect(action->getLine(), enterPoint)) {

	    // See if the intersection is within the correct radius
	    // and is within the clipping planes
	    float distFromYAxisSquared = (enterPoint[0] * enterPoint[0] +
					  enterPoint[2] * enterPoint[2]);

	    if (distFromYAxisSquared <= radius * radius) {

		numHits++;

		if (action->isBetweenPlanes(enterPoint) &&
		    (pp = action->addIntersection(enterPoint)) != NULL) {
		    pp->setObjectNormal(norm);
		    texCoord.setValue(0.5 + enterPoint[0] / (2.0 * radius),
				      0.5 - enterPoint[2] / (2.0 * radius),
				      0.0, 1.0);
		    pp->setObjectTextureCoords(texCoord);
		    if (materialPerPart)
			pp->setMaterialIndex(1);
		    detail = new SoCylinderDetail();
		    detail->setPart(TOP);
		    pp->setDetail(detail, this);
		}
	    }
	}
    }

    // If we haven't hit the cylinder twice already, check for an
    // intersection with the bottom face
    if (numHits < 2 && HAS_PART(curParts, BOTTOM)) {
	SbVec3f	norm(0.0, -1.0, 0.0);

	// Construct a plane containing the bottom face
	SbPlane		bottomFacePlane(norm, halfHeight);

	// See if the ray hits this plane
	if (bottomFacePlane.intersect(action->getLine(), enterPoint)) {

	    // See if the intersection is within the correct radius
	    // and is within the clipping planes
	    float distFromYAxisSquared = (enterPoint[0] * enterPoint[0] +
					  enterPoint[2] * enterPoint[2]);

	    if (distFromYAxisSquared <= radius * radius &&
		action->isBetweenPlanes(enterPoint) &&
		(pp = action->addIntersection(enterPoint)) != NULL) {
		pp->setObjectNormal(norm);
		texCoord.setValue(0.5 + enterPoint[0] / (2.0 * radius),
				  0.5 + enterPoint[2] / (2.0 * radius),
				  0.0, 1.0);
		pp->setObjectTextureCoords(texCoord);
		if (materialPerPart)
		    pp->setMaterialIndex(2);
		detail = new SoCylinderDetail();
		detail->setPart(BOTTOM);
		pp->setDetail(detail, this);
	    }
	}
    }
}
Exemplo n.º 6
0
/*!
  This is called once to generate the child nodes that make up this
  complex shape.  The child nodes consist of a cylinder, transforms, and
  cones.  A calculator node caluculates the height of the cylinder from
  the total height field and the height of any present arrowheads.
*/
void
SoArrow::generateChildren()
{
  // This should be called once, that means children
  // doesn not have any children yet.
  assert(children->getLength() == 0);

  // Construct the begin arrowhead
  SoCone *cne = new SoCone;
  cne->height.connectFrom(&coneHeight);
  cne->bottomRadius.connectFrom(&coneRadius);

  SoTransform *beginTran = new SoTransform;
  beginTran->rotation.setValue(SbVec3f(1, 0, 0), (float)M_PI);

  SoSeparator *beginSep = new SoSeparator;
  beginSep->addChild(beginTran);
  beginSep->addChild(cne);
  beginSw = new SoSwitch;
  beginSw->addChild(beginSep);

  // Construct the end arrowhead
  SoTranslation *endTran = new SoTranslation;

  SoSeparator *endSep = new SoSeparator;
  endSep->addChild(endTran);
  endSep->addChild(cne);
  endSw = new SoSwitch;
  endSw->addChild(endSep);

  // Move the arrowheads to the ends of the shaft
  calEngine = new SoCalculator;
  calEngine->a.connectFrom(&height);
  calEngine->b.connectFrom(&coneHeight);

  if (HAS_PART(arrowHeads.getValue(), SoArrow::BEGIN)) {
    calEngine->c.setValue(1);
    beginSw->whichChild.setValue(SO_SWITCH_ALL);
  }
  else {
    calEngine->c.setValue(0);
    beginSw->whichChild.setValue(SO_SWITCH_NONE);
  }

  if (HAS_PART(arrowHeads.getValue(), SoArrow::END)) {
    calEngine->d.setValue(1);
    endSw->whichChild.setValue(SO_SWITCH_ALL);
  }
  else {
    calEngine->d.setValue(0);
    endSw->whichChild.setValue(SO_SWITCH_NONE);
  }

  // Calculate the height of the shaft
  calEngine->expression.set1Value(0, "oa = a - c*b - d*b");

  // Compute the position where the begin cone needs to be moved to
  calEngine->expression.set1Value(1, "oA = vec3f(0.0, b/2.0, 0.0)");
  // Compute the position where the end cone needs to be moved to
  calEngine->expression.set1Value(2, "oB = vec3f(0.0, a - b/2.0, 0.0)");
  // Compute the position where the shaft needs to be moved to
  calEngine->expression.set1Value(3, "oC = vec3f(0.0, oa/2.0 + c*b, 0.0)");

  beginTran->translation.connectFrom(&calEngine->oA);
  endTran->translation.connectFrom(&calEngine->oB);

  SoCylinder *shaft = new SoCylinder;
  shaft->radius.connectFrom(&cylRadius);
  shaft->height.connectFrom(&calEngine->oa);

  SoTranslation *shaftTran = new SoTranslation;
  shaftTran->translation.connectFrom(&calEngine->oC);

  SoSeparator *root = new SoSeparator;
  root->addChild(beginSw);
  root->addChild(endSw);
  root->addChild(shaftTran);
  root->addChild(shaft);

  children->append(root);
}
Exemplo n.º 7
0
/*!
  Returns whether a given part is on or off.
*/
SbBool
SoArrow::hasPart(Part part) const
{
  return HAS_PART(arrowHeads.getValue(), part);
}