#include #include #include #include #include #include "strip.h" using namespace std; extern "C" ygNode* construct_strip(const char* name,bool master) { return new strip(name,master); } struct _stripPrivateData { bool firstFrame; ygString textureFile; pfVec3 * vertices; int length; }; strip::strip(const char* name,bool master) : ygNode(name,master) { setClassName("strip"); p_ = new struct _stripPrivateData; p_->firstFrame = true; p_->length = 8; } strip::~strip(void) { delete p_; } void strip::reset(void) { ygNode::reset(); } void strip::message(const ygMessage& msg) { if (msg == "texture") { p_->textureFile = msg.stringArg(0); } else if (msg == "length") { p_->length = msg.intArg(0); } else ygNode::message(msg); } void strip::app(void) { int x, index; if (p_->firstFrame) { createStrip(); p_->firstFrame = false; } for (x = 0, index = 0; x <= p_->length; x++) { p_->vertices[index].set(x,1,drand48()); index++; p_->vertices[index].set(x,0,drand48()); index++; } ygNode::app(); } /** This function will create a geode that contains a single triangle strip with partially random vertices. The 'length' message sets the number of squares in the strip (thus there are 2*length triangles). If a texture map was specified (by the 'texture' message), it will be applied to the strip via its geostate, and texture coordinates will be calculated for the geoset. **/ void strip::createStrip(void) { /* Create the three basic objects involved */ pfGeode * geode = new pfGeode; pfGeoSet * geoset = new pfGeoSet; pfGeoState * geostate = new pfGeoState; int *lengths; pfVec3 * normals; pfVec4 * colors; int numVertices, x, index; numVertices = p_->length * 2 + 2; /* It will be one triangle strip, with 2*length+2 vertices */ geoset->setPrimType(PFGS_TRISTRIPS); geoset->setNumPrims(1); lengths = (int *) pfMalloc(sizeof(int),pfGetSharedArena()); lengths[0] = numVertices; geoset->setPrimLengths(lengths); /* Create an array for the vertex coordinates, fill it with data (the Z will be random), and assign it to the geoset */ p_->vertices = (pfVec3*) pfMalloc(numVertices * sizeof(pfVec3), pfGetSharedArena()); for (x = 0, index = 0; x <= p_->length; x++) { p_->vertices[index].set(x,1,drand48()); index++; p_->vertices[index].set(x,0,drand48()); index++; } geoset->setAttr(PFGS_COORD3, PFGS_PER_VERTEX, p_->vertices, NULL); /* Compute a normal for each vertex, by taking the cross product of two triangle edges that it's part of. */ normals = (pfVec3*) pfMalloc(numVertices * sizeof(pfVec3), pfGetSharedArena()); normals[0].set(0, 0, 1); for (index = 1; index < numVertices-1; index++) { pfVec3 edge1, edge2; edge1 = p_->vertices[index-1] - p_->vertices[index]; edge1.normalize(); edge2 = p_->vertices[index+1] - p_->vertices[index]; edge2.normalize(); normals[index].cross(edge1,edge2); } normals[index].set(0,0,1); geoset->setAttr(PFGS_NORMAL3, PFGS_PER_VERTEX, normals, NULL); /* Assign a single, overall red color to the geoset */ colors = (pfVec4*) pfMalloc(sizeof(pfVec4), pfGetSharedArena()); colors[0].set(1,0,0,1); geoset->setAttr(PFGS_COLOR4, PFGS_OVERALL, colors, NULL); if (p_->textureFile.length() > 0) { /* Compute texture coordinates so that the texture image will cover the strip once */ pfVec2 * texcoords; pfTexture * texture; texcoords = (pfVec2*) pfMalloc(numVertices * sizeof(pfVec2), pfGetSharedArena()); for (x = 0, index = 0; x <= p_->length; x++) { texcoords[index].set(((float)x)/p_->length, 1); index++; texcoords[index].set(((float)x)/p_->length, 0); index++; } geoset->setAttr(PFGS_TEXCOORD2, PFGS_PER_VERTEX, texcoords, NULL); /* Create the texture object, assign it to the geostate, and enable texturing */ texture = new pfTexture; texture->loadFile(p_->textureFile.c_str()); geostate->setAttr(PFSTATE_TEXTURE, texture); geostate->setMode(PFSTATE_ENTEXTURE, PF_ON); } /* Create a material object for the geostate, and enable lighting */ pfMaterial * material = new pfMaterial; geostate->setAttr(PFSTATE_FRONTMTL, material); geostate->setMode(PFSTATE_ENLIGHTING, PF_ON); /* Put everything together, and stick it in the scene graph */ geoset->setGState(geostate); geode->addGSet(geoset); pfnode()->addChild(geode); }