/* * NodeSuperShape.cpp * * Copyright (C) 1999 Stephen F. White, 2004 J. "MUFTI" Scheurich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file "COPYING" for details); if * not, write to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. */ #include #include "stdafx.h" #include "NodeSuperShape.h" #include "Proto.h" #include "DuneApp.h" #include "FieldValue.h" #include "Scene.h" #include "Mesh.h" #include "SFFloat.h" #include "SFInt32.h" #include "SFBool.h" #include "NodeIndexedFaceSet.h" #include "NodeCoordinate.h" #include "NodeNormal.h" #include "NodeTextureCoordinate.h" #include "NodeNurbsSurface.h" ProtoSuperShape::ProtoSuperShape(Scene *scene) : Proto(scene, "SuperShape") { ua.set( addExposedField(SFFLOAT, "ua", new SFFloat(1.0f))); ub.set( addExposedField(SFFLOAT, "ub", new SFFloat(1.0f))); um.set( addExposedField(SFFLOAT, "um", new SFFloat(0.0f))); un1.set( addExposedField(SFFLOAT, "un1", new SFFloat(1.0f))); un2.set( addExposedField(SFFLOAT, "un2", new SFFloat(1.0f))); un3.set( addExposedField(SFFLOAT, "un3", new SFFloat(1.0f))); va.set( addExposedField(SFFLOAT, "va", new SFFloat(1.0f))); vb.set( addExposedField(SFFLOAT, "vb", new SFFloat(1.0f))); vm.set( addExposedField(SFFLOAT, "vm", new SFFloat(0.0f))); vn1.set( addExposedField(SFFLOAT, "vn1", new SFFloat(1.0f))); vn2.set( addExposedField(SFFLOAT, "vn2", new SFFloat(1.0f))); vn3.set( addExposedField(SFFLOAT, "vn3", new SFFloat(1.0f))); border.set( addExposedField(SFFLOAT, "border", new SFFloat(M_PI / 2.0), new SFFloat(-M_PI / 2.0), new SFFloat(M_PI / 2.0))); creaseAngle.set( addField(SFFLOAT, "creaseAngle", new SFFloat(0.7854f), new SFFloat(0.0f))); texCoord.set( addExposedField(SFNODE, "texCoord", new SFNode(NULL), TEXTURE_COORDINATE_NODE)); uTessellation.set( addExposedField(SFINT32, "uTessellation", new SFInt32(0))); vTessellation.set( addExposedField(SFINT32, "vTessellation", new SFInt32(0))); } Node * ProtoSuperShape::create(Scene *scene) { return new NodeSuperShape(scene, this); } NodeSuperShape::NodeSuperShape(Scene *scene, Proto *def) : MeshBasedNode(scene, def) { } NodeSuperShape::~NodeSuperShape() { } static float superFormula(float angle, float a, float b, float m, float n1, float n2, float n3) { float f = m * angle / 4.0; float c = cos(f); float s = sin(f); return pow(pow(fabs(c / a), n2) + pow(fabs(s / b), n3), -1.0 / n1); } void NodeSuperShape::createMesh() { if (_mesh) delete _mesh; _mesh = NULL; int uTess = uTessellation()->getValue(); int vTess = vTessellation()->getValue(); if (uTess <= 0) uTess = 32; if (vTess <= 0) vTess = 32; uTess++; vTess++; if (uTess < 3) return; if (vTess < 3) return; int size = uTess * vTess; Vec3f *vert = new Vec3f[size]; int* ci = new int[(uTess + 1) * (vTess + 1) * 5]; float low = -M_PI / 2.0; float high = border()->getValue(); float inc1 = M_PI / (uTess-1) * 2.0; float inc2 = (high - low) / (vTess-1); if (inc2 < EPSILON) return; int a1; int a2; float fua = ua()->getValue(); float fub = ub()->getValue(); float fum = um()->getValue(); float fun1 = un1()->getValue(); float fun2 = un2()->getValue(); float fun3 = un3()->getValue(); Array r1(uTess); Array c1(uTess); Array s1(uTess); for (a1 = 0; a1 < uTess; a1++) { float angle1 = -M_PI + a1 * inc1; r1[a1] = superFormula(angle1, fua, fub, fum, fun1, fun2, fun3); c1[a1] = cos(angle1); s1[a1] = sin(angle1); } float fva = va()->getValue(); float fvb = vb()->getValue(); float fvm = vm()->getValue(); float fvn1 = vn1()->getValue(); float fvn2 = vn2()->getValue(); float fvn3 = vn3()->getValue(); Array r2(vTess); Array c2(vTess); Array s2(vTess); for (a2 = 0; a2 < vTess; a2++) { float angle2 = low + a2 * inc2; r2[a2] = superFormula(angle2, fva, fvb, fvm, fvn1, fvn2, fvn3); c2[a2] = cos(angle2); s2[a2] = sin(angle2); } int index = 0; int cindex = 0; for (a2 = 0; a2 < vTess; a2++) { for (a1 = 0; a1 < uTess; a1++) { vert[index].z = r1[a1] * c1[a1] * r2[a2] * c2[a2]; vert[index].x = r1[a1] * s1[a1] * r2[a2] * c2[a2]; vert[index].y = r2[a2] * s2[a2]; index++; int c1 = a1 + 1; if (a1 == uTess - 1) continue; int c2 = a2 + 1; if (a2 == vTess - 1) continue; ci[cindex++] = a1 + a2 * uTess; ci[cindex++] = c1 + a2 * uTess; ci[cindex++] = c1 + c2 * uTess; ci[cindex++] = a1 + c2 * uTess; ci[cindex++] = -1; } } cindex = cleanDoubleVertices(ci, vert, NULL, cindex); MFVec3f *vertices = new MFVec3f((float *) vert, size * 3); MFInt32 *coordIndex = new MFInt32(ci, cindex); MFVec2f *texCoords = NULL; if (texCoord()->getValue()) { if (texCoord()->getValue()->getType() == NODE_TEXTURE_COORDINATE) texCoords = ((NodeTextureCoordinate *)(texCoord()->getValue())) ->point(); } else texCoords = generateTextureCoordinates(vertices, coordIndex); bool solid = false; if (high == M_PI / 2.0) solid = true; int meshFlags = MESH_CCW; if (solid) meshFlags |= MESH_SOLID; _mesh = new Mesh(vertices, coordIndex, NULL, NULL, NULL, NULL, texCoords, NULL, creaseAngle()->getValue(), meshFlags); } bool NodeSuperShape::writeEXTERNPROTO(int f) { RET_ONERROR( mywritestr(f ,"EXTERNPROTO SuperShape[\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat ua\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat ub\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat um\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat un1\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat un2\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat un3\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat va\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat vb\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat vm\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat vn1\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat vn2\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat vn3\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat border\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," field SFFloat creaseAngle\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," field SFNode texCoord\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFInt32 uTessellation\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFInt32 vTessellation\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," ]\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ,"[\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ,"# \"") ) RET_ONERROR( mywritestr(f ,"SuperShapePROTO.wrl") ) RET_ONERROR( mywritestr(f ,"\"\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ,"\"") ) char *dunedocs = getenv("DUNEDOCS"); if (dunedocs != NULL) { RET_ONERROR( mywritestr(f ,dunedocs) ) RET_ONERROR( mywritestr(f ,"/scriptedNodes") ) } #ifdef HAVE_SCRIPTED_NODES_PROTO_URL else RET_ONERROR( mywritestr(f ,HAVE_SCRIPTED_NODES_PROTO_URL) ) #endif RET_ONERROR( mywritestr(f ,"/") ) RET_ONERROR( mywritestr(f ,"SuperShapePROTO.wrl") ) RET_ONERROR( mywritestr(f ,"\"\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," \"http://www.csv.ica.uni-stuttgart.de/vrml/dune/docs/scriptedNodes/SuperShapePROTO.wrl\"\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ,"]\n") ) TheApp->incSelectionLinenumber(); return true; } int NodeSuperShape::write(int filedes, int indent) { if (_scene->isPureVRML97()) { Node *node = toIndexedFaceSet(); if (node == NULL) return 1; RET_ONERROR( node->write(filedes, indent) ) node->unref(); } else RET_ONERROR( NodeData::write(filedes, indent) ) return 0; } void NodeSuperShape::setField(int index, FieldValue *value) { _meshDirty = true; Node::setField(index, value); } Node* NodeSuperShape::toNurbs(int uTess, int vTess, int uDegree, int vDegree) { if (_meshDirty) { createMesh(); _meshDirty = false; } NodeNurbsSurface *node = (NodeNurbsSurface *) _scene->createNode( "NurbsSurface"); int vOrder = vDegree + 1; int uOrder = uDegree + 1; int oldUTess = uTessellation()->getValue(); int oldVTess = vTessellation()->getValue(); bool storeOldTesselation = false; if ((oldUTess != uTess) || (oldVTess != vTess)) { storeOldTesselation = true; uTessellation(new SFInt32(uTess)); vTessellation(new SFInt32(vTess)); createMesh(); _meshDirty = true; } uTess++; vTess++; int size = _mesh->getVertices()->getSize(); int uDimension = uTess; int vDimension = vTess; float *controlPoints = new float[size]; float *weights = new float[size]; float *uKnots = new float[uDimension + uOrder]; float *vKnots = new float[vDimension + vOrder]; int i; for (i = 0; i < size; i++){ controlPoints[i] = _mesh->getVertices()->getValues()[i]; } for(i = 0; i < size; i++){ weights[i] = 1; } //set u-knotvektor for(i = 0; i < uOrder; i++){ uKnots[i] = 0.0f; uKnots[i + uDimension] = (float) (uDimension - uOrder + 1); } for(i = 0; i < (uDimension - uOrder); i++){ uKnots[i + uOrder] = (float) (i + 1); } //set v-knotvektor for(i = 0; i < vOrder; i++){ vKnots[i] = 0.0f; vKnots[i + vDimension] = (float) (vDimension - vOrder + 1); } for(i = 0; i < (vDimension - vOrder); i++){ vKnots[i + vOrder] = (float) (i + 1); } node->setField(node->uDimension_Index(), new SFInt32(uDimension)); node->setField(node->vDimension_Index(), new SFInt32(vDimension)); node->uKnot(new MFFloat(uKnots, uDimension + uOrder)); node->vKnot(new MFFloat(vKnots, vDimension + vOrder)); node->setField(node->uOrder_Index(), new SFInt32(uOrder)); node->setField(node->vOrder_Index(), new SFInt32(vOrder)); node->controlPoint(new MFVec3f(controlPoints, uDimension * vDimension * 3)); node->weight(new MFFloat(weights, uDimension * vDimension)); node->ccw(new SFBool(_mesh->ccw())); node->solid(new SFBool(_mesh->solid())); node->setField(node->uTessellation_Index(), new SFInt32(uTess-1)); node->setField(node->vTessellation_Index(), new SFInt32(vTess-1)); for (int iteration = 0; iteration < 2; iteration++) { node->reInit(); node->createMesh(); if (node->getVertices() != NULL) { assert(size == node->getVertices()->getSize()); float *vert = new float[size]; MFVec3f *nurbsControlPoints = node->controlPoint(); for (i = 0; i < size; i++) { vert[i] = node->getVertices()->getValues()[i]; float meshValue =_mesh->getVertices()->getValues()[i]; float nurbsValue = nurbsControlPoints->getValues()[i]; if (fabs(vert[i]) > EPSILON) { vert[i] = nurbsValue + nurbsValue * meshValue / vert[i]; vert[i] = vert[i] / 2.0; } } for (i = 0; i < size; i++) { nurbsControlPoints->setValue(i, vert[i]); } } } node->setField(node->uTessellation_Index(), new SFInt32(0)); node->setField(node->vTessellation_Index(), new SFInt32(0)); if (storeOldTesselation) { uTessellation(new SFInt32(oldUTess)); vTessellation(new SFInt32(oldVTess)); } return node; }