// // ivexport.C // // writes out a .iv file, reflecting a pf scene graph, // to be used with SGI's OpenGL|Perfomer libpfiv // (c)2006 Bram Stolk (bram at sara.nl) // You may distribute this file, modified or not, as long as the // original copyright message is maintained. // // SUPPORTED: // - LINES // - LINESTRIPS // - TRISTRIPS (flat / normal) // - POLYS // - QUADS // - POINTS // - Textures (rgb, jpg, gif) // - SCS,DCS,Group,Switch // // LIMITATIONS: // - No tri fans // - No flat linestrips // - texture bleed? // - texture quality is not optimal? transparent texture? filtering? // - pfSequence is written as SoSwitch, which is not the same thing. // - Animation not supported // - BACKMTL not supported // - No pfLayer support // // Fri Feb 3 23:20:42 CET 2006 // Version 1.0 // #include #include #include #include #include #include #include #include #include #include #include #include #define INDENT(L) \ fwrite(indentation, (L)*2>128?128:(L)*2, 1, f); extern "C" { int pfdStoreFile_iv(pfNode *root, const char *fname); } static const char *indentation=" "; static const char *prim_type_name(int t) { if (t==PFGS_POINTS) return "PFGS_POINTS"; if (t==PFGS_LINES) return "PFGS_LINES"; if (t==PFGS_LINESTRIPS) return "PFGS_LINESTRIPS"; if (t==PFGS_FLAT_LINESTRIPS) return "PFGS_FLAT_LINESTRIPS"; if (t==PFGS_TRIS) return "PFGS_TRIS"; if (t==PFGS_QUADS) return "PFGS_QUADS"; if (t==PFGS_TRISTRIPS) return "PFGS_TRISTRIPS"; if (t==PFGS_FLAT_TRISTRIPS) return "PFGS_FLAT_TRISTRIPS"; if (t==PFGS_TRIFANS) return "PFGS_TRIFANS"; if (t==PFGS_FLAT_TRIFANS) return "PFGS_FLAT_TRIFANS"; if (t==PFGS_POLYS) return "PFGS_POLYS"; return 0; } static const char *get_bind_name(int bd) { if (bd == PFGS_OVERALL) return "OVERALL"; if (bd == PFGS_PER_PRIM) return "PER_PART"; if (bd == PFGS_PER_VERTEX) return "PER_VERTEX"; return "OFF"; } static const char *get_cmode_name(int cmode) { if (cmode == PFMTL_CMODE_AMBIENT_AND_DIFFUSE) return "PFMTL_CMODE_AMBIENT_AND_DIFFUSE"; if (cmode == PFMTL_CMODE_AMBIENT) return "PFMTL_CMODE_AMBIENT"; if (cmode == PFMTL_CMODE_DIFFUSE) return "PFMTL_CMODE_DIFFUSE"; if (cmode == PFMTL_CMODE_EMISSION) return "PFMTL_CMODE_EMISSION"; if (cmode == PFMTL_CMODE_SPECULAR) return "PFMTL_CMODE_SPECULAR"; if (cmode == PFMTL_CMODE_OFF) return "PFMTL_CMODE_OFF"; if (cmode == PFMTL_CMODE_COLOR) return "PFMTL_CMODE_COLOR"; pfNotify(PFNFY_WARN, PFNFY_USAGE, "Unsupported cmode %d", cmode); return 0; } int store_geostate(pfGeoState *gstate, FILE *f, int lvl) { const char *texturename = 0; assert(gstate); int cmode=-1; int entexture = gstate->getMode(PFSTATE_ENTEXTURE); if (entexture == PF_ON) { pfTexEnv *texenv = (pfTexEnv*) gstate->getAttr(PFSTATE_TEXENV); pfTexture *texture = (pfTexture*)gstate->getAttr(PFSTATE_TEXTURE); if (texture) { texturename = texture->getName(); INDENT(lvl); fprintf(f, "#Texture at %p named %s texenv at %p\n", texture, texturename, texenv); } } pfMaterial *fmaterial = (pfMaterial*)gstate->getAttr(PFSTATE_FRONTMTL); pfMaterial *bmaterial = (pfMaterial*)gstate->getAttr(PFSTATE_BACKMTL); INDENT(lvl); fprintf(f,"#frontmat %p backmat %p\n", fmaterial, bmaterial); pfLightModel *lightmodel = (pfLightModel*)gstate->getAttr(PFSTATE_LIGHTMODEL); if (lightmodel) if (lightmodel->getTwoSide() == PF_ON) { INDENT(lvl); fprintf(f, "ShapeHints { vertexOrdering COUNTERCLOCKWISE shapeType UNKNOWN_SHAPE_TYPE }\n"); } bool lighting = gstate->getMode(PFSTATE_ENLIGHTING); if (!lighting) { INDENT(lvl); fprintf(f, "LightModel { model BASE_COLOR }\n"); } pfMaterial *material = fmaterial; if (fmaterial) { cmode = material->getColorMode(PFMTL_FRONT); INDENT(lvl); fprintf(f, "Material { "); float r,g,b; material->getColor(PFMTL_DIFFUSE, &r,&g,&b); fprintf(f,"diffuseColor %.3f %.3f %.3f ", r,g,b); material->getColor(PFMTL_AMBIENT, &r,&g,&b); fprintf(f,"ambientColor %.3f %.3f %.3f ", r,g,b); material->getColor(PFMTL_EMISSION, &r,&g,&b); fprintf(f,"emissiveColor %.3f %.3f %.3f ", r,g,b); material->getColor(PFMTL_SPECULAR, &r,&g,&b); fprintf(f,"specularColor %.3f %.3f %.3f ", r,g,b); float a = material->getAlpha(); // Yuck! Inventor does not do exponent shininess, but want a value from 0 to 1. float s = material->getShininess() / 128.0; fprintf(f,"shininess %.3f transparency %.3f ", s, 1.0-a); fprintf(f, "}\n"); } if (texturename) { INDENT(lvl); fprintf(f, "Texture2 { filename \"%s\" }\n", texturename); } return cmode; } int store_geoset(pfGeoSet *gset, FILE *f, int lvl) { int primtp = gset->getPrimType(); const char *typn = prim_type_name(primtp); int numprims = gset->getNumPrims(); int minc,maxc,minn,maxn,mint,maxt,minv,maxv; int nc = gset->getAttrRange(PFGS_COLOR4, &minc, &maxc); int nn = gset->getAttrRange(PFGS_NORMAL3, &minn, &maxn); int nt = gset->getAttrRange(PFGS_TEXCOORD2, &mint, &maxt); int nv = gset->getAttrRange(PFGS_COORD3, &minv, &maxv); INDENT(lvl); fprintf(f, "#%s with %d primitives nc=%d nn=%d nt=%d nv=%d\n", typn, numprims, nc, nn, nt, nv); unsigned short *idxc=0, *idxn=0, *idxt=0, *idxv=0; pfVec4 *lc=0; pfVec3 *ln=0; pfVec2 *lt=0; pfVec3 *lv=0; gset->getAttrLists(PFGS_COLOR4, (void**) &lc, &idxc); gset->getAttrLists(PFGS_NORMAL3, (void**) &ln, &idxn); gset->getAttrLists(PFGS_TEXCOORD2, (void**) <, &idxt); gset->getAttrLists(PFGS_COORD3, (void**) &lv, &idxv); int i; // Flatten the indexing if (maxv>0) { pfVec3 *flatv = new pfVec3[nv]; for (i=0; i0) { pfVec3 *flatn = new pfVec3[nn]; for (i=0; i0) { pfVec4 *flatc = new pfVec4[nc]; for (i=0; i0) { pfVec2 *flatt = new pfVec2[nt]; for (i=0; i0) || (maxn>0) || (maxv>0) || (maxt>0); if (indexed) { INDENT(lvl); fprintf(f,"#indices ranges from,to: v(%d,%d), n(%d,%d), c(%d,%d), t(%d,%d)\n", minv,maxv, minn,maxn, minc,maxc, mint,maxt); } pfGeoState *gstate = 0; gstate = gset->getGState(); int cmode=-1; if (gstate) { INDENT(lvl); fprintf(f,"#GeoState %p\n", gstate); cmode = store_geostate(gstate, f, lvl); if (cmode != -1) { const char *cmodename = get_cmode_name(cmode); INDENT(lvl); fprintf(f,"#cmode: %s\n", cmodename); } } else { INDENT(lvl); fprintf(f,"#No geostate defined\n"); } INDENT(lvl); fprintf(f, "SoVertexProperty {\n"); int bd; bd = gset->getAttrBind(PFGS_COLOR4); const char *bindn = get_bind_name(bd); if (primtp == PFGS_FLAT_TRISTRIPS && bindn == "PER_VERTEX") bindn = "PER_FACE"; if (bindn!="OFF") { INDENT(lvl+1); fprintf(f, "materialBinding %s%s\n", bindn, ""); } bd = gset->getAttrBind(PFGS_NORMAL3); bindn = get_bind_name(bd); if (primtp == PFGS_FLAT_TRISTRIPS && bindn == "PER_VERTEX") bindn = "PER_FACE"; if (bindn!="OFF") { INDENT(lvl+1); fprintf(f, "normalBinding %s%s\n", bindn, ""); } bd = gset->getAttrBind(PFGS_TEXCOORD2); if (bd != PFGS_OFF) assert(bd == gset->getAttrBind(PFGS_COORD3)); INDENT(lvl+1); fprintf(f, "vertex ["); for (i=0; igetPrimLength(i)); fprintf(f,"]\n"); INDENT(lvl); fprintf(f, "}\n"); return true; } if (primtp == PFGS_QUADS) { INDENT(lvl); fprintf(f, "FaceSet {\n"); INDENT(lvl+1); fprintf(f, "numVertices ["); for (i=0; igetPntSize(); INDENT(lvl); fprintf(f, "DrawStyle { pointSize %f }\n", psz); INDENT(lvl); fprintf(f, "PointSet {\n"); INDENT(lvl+1); fprintf(f, "numPoints %d", numprims); INDENT(lvl); fprintf(f, "}\n"); return true; } if (primtp == PFGS_LINESTRIPS) { float lw = gset->getLineWidth(); INDENT(lvl); fprintf(f, "DrawStyle { lineWidth %f }\n", lw); INDENT(lvl); fprintf(f, "LineSet {\n"); INDENT(lvl+1); fprintf(f, "numVertices ["); for (i=0; igetPrimLength(i)); fprintf(f,"]\n"); INDENT(lvl); fprintf(f, "}\n"); return true; } if (primtp == PFGS_LINES) { float lw = gset->getLineWidth(); INDENT(lvl); fprintf(f, "DrawStyle { lineWidth %f }\n", lw); INDENT(lvl); fprintf(f, "LineSet {\n"); INDENT(lvl+1); fprintf(f, "numVertices ["); for (i=0; igetName(); if (!name) name = ""; INDENT(lvl); fprintf(f,"#%s %s\n", node->getTypeName(), name); if (node->getType() == pfGeode::getClassType()) { pfGeode *geode = dynamic_cast(node); assert(geode); for (int i=0; igetNumGSets(); i++) { INDENT(lvl); fprintf(f,"Separator {\n"); store_geoset(geode->getGSet(i), f, lvl+1); INDENT(lvl); fprintf(f,"}\n"); } return true; } if (node->getType() == pfLOD::getClassType()) { pfLOD *lod = dynamic_cast(node); assert(lod); INDENT(lvl); fprintf(f,"LOD {\n"); int nc = lod->getNumChildren(); for (int k=0; kgetChild(k), f, lvl+1); INDENT(lvl); fprintf(f,"}\n"); return true; } if (node->isOfType(pfSCS::getClassType())) { pfSCS *scs = dynamic_cast(node); assert(scs); INDENT(lvl); fprintf(f,"Separator {\n"); INDENT(lvl+1); fprintf(f,"MatrixTransform { matrix\n"); pfMatrix mat; scs->getMat(mat); for (int r=0; r<4; r++) { pfVec3 row; mat.getRow(r, row); INDENT(lvl+2); fprintf(f,"%f %f %f %d\n", row[0], row[1], row[2], (r==3)?1:0); } INDENT(lvl+1); fprintf(f,"}\n"); int nc = scs->getNumChildren(); for (int k=0; kgetChild(k), f, lvl+1); INDENT(lvl); fprintf(f,"}\n"); return true; } if (node->isOfType(pfSequence::getClassType())) { pfSequence *seq = dynamic_cast(node); assert(seq); INDENT(lvl); fprintf(f,"Switch {\n"); INDENT(lvl+1); fprintf(f,"whichChild 0\n"); int nc = seq->getNumChildren(); for (int k=0; kgetChild(k), f, lvl+1); INDENT(lvl); fprintf(f,"}\n"); return true; } if (node->isOfType(pfSwitch::getClassType())) { pfSwitch *sw = dynamic_cast(node); assert(sw); INDENT(lvl); fprintf(f,"Switch {\n"); int v = (int)sw->getVal(); if (v == PFSWITCH_ON) v = -3; if (v == PFSWITCH_OFF) v = -1; INDENT(lvl+1); fprintf(f,"whichChild %d\n", v); int nc = sw->getNumChildren(); for (int k=0; kgetChild(k), f, lvl+1); INDENT(lvl); fprintf(f,"}\n"); return true; } if (node->isOfType(pfGroup::getClassType())) { pfGroup *group = dynamic_cast(node); assert(group); INDENT(lvl); fprintf(f,"Group {\n"); int nc = group->getNumChildren(); for (int k=0; kgetChild(k), f, lvl+1); INDENT(lvl); fprintf(f,"}\n"); return true; } pfNotify(PFNFY_WARN, PFNFY_USAGE, "Unsupported node type %s", node->getTypeName()); return false; } int pfdStoreFile_iv(pfNode *root, const char *fname) { FILE *f=fopen(fname,"w"); if (!f) return false; fprintf(f,"#Inventor V2.0 ascii\n"); fprintf(f,"#Generated by pfdStoreFile_iv() by Bram Stolk\n"); store_node(root, f); fclose(f); return true; }