/* * NodeNurbsTextureSurface.cpp * * Copyright (C) 1999 Stephen F. White * * 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 #ifndef _WIN32 # include "stdlib.h" #endif #include "stdafx.h" #include "NodeNurbsTextureSurface.h" #include "Scene.h" #include "FieldValue.h" #include "SFInt32.h" #include "MFFloat.h" #include "MFInt32.h" #include "MFVec2f.h" #include "MFVec3f.h" #include "SFNode.h" #include "SFBool.h" #include "SFVec3f.h" #include "Vec2f.h" #include "Vec3f.h" #include "RenderState.h" #include "DuneApp.h" #include "NodeCoordinate.h" #include "NodeNormal.h" #include "NodeTextureCoordinate.h" #include "NodeIndexedFaceSet.h" #include "NodeNurbsGroup.h" #include "NurbsSurfaceDegreeElevate.h" #include "Util.h" #include "Field.h" #include "ExposedField.h" ProtoNurbsTextureSurface::ProtoNurbsTextureSurface(Scene *scene) : Proto(scene, "NurbsTextureSurface") { uDimension.set( addField(SFINT32, "uDimension", new SFInt32(0), new SFInt32(0))); vDimension.set( addField(SFINT32, "vDimension", new SFInt32(0), new SFInt32(0))); uKnot.set( addField(MFFLOAT, "uKnot", new MFFloat())); vKnot.set( addField(MFFLOAT, "vKnot", new MFFloat())); uOrder.set( addField(SFINT32, "uOrder", new SFInt32(3), new SFInt32(2))); vOrder.set( addField(SFINT32, "vOrder", new SFInt32(3), new SFInt32(2))); ExposedField* cpoint = new ExposedField(MFVEC3F, "controlPoint", new MFVec3f()); controlPoint.set(addExposedField(cpoint)); weight.set( addExposedField(MFFLOAT, "weight", new MFFloat(), new SFFloat(0.0f))); uTessellation.set( addExposedField(SFINT32, "uTessellation", new SFInt32(0))); vTessellation.set( addExposedField(SFINT32, "vTessellation", new SFInt32(0))); } Node * ProtoNurbsTextureSurface::create(Scene *scene) { return new NodeNurbsTextureSurface(scene, this); } NodeNurbsTextureSurface::NodeNurbsTextureSurface(Scene *scene, Proto *proto) : Node(scene, proto) { } NodeNurbsTextureSurface::~NodeNurbsTextureSurface() { } void NodeNurbsTextureSurface::drawHandles() { int iuDimension = uDimension()->getValue(); int ivDimension = vDimension()->getValue(); RenderState state; if (controlPoint()->getSize() != iuDimension * ivDimension * 3) return; if (weight()->getSize() != iuDimension * ivDimension) { return; } glPushName(iuDimension * ivDimension + 1); glDisable(GL_LIGHTING); Util::myGlColor3f(1.0f, 1.0f, 1.0f); if (TheApp->GetHandleMeshAlways() || (_scene->getSelectedHandle() == -1)) { for (int i = 0; i < iuDimension; i++) { glBegin(GL_LINE_STRIP); for (int j = 0; j < ivDimension; j++) { const float *v = controlPoint()->getValue(i + j*iuDimension); float w = weight()->getValue(i + j*iuDimension); glVertex3f(v[0] / w, v[1] / w, v[2] / w); } glEnd(); } for (int j = 0; j < ivDimension; j++) { glBegin(GL_LINE_STRIP); for (int i = 0; i < iuDimension; i++) { const float *v = controlPoint()->getValue(i + j*iuDimension); float w = weight()->getValue(i + j*iuDimension); glVertex3f(v[0] / w, v[1] / w, v[2] / w); } glEnd(); } } state.startDrawHandles(); for (int ci = 0; ci < iuDimension * ivDimension; ci++) { glLoadName(ci); state.drawHandle( Vec3f(controlPoint()->getValue(ci)) / weight()->getValue(ci)); } state.endDrawHandles(); glPopName(); glEnable(GL_LIGHTING); } Vec3f NodeNurbsTextureSurface::getHandle(int handle, int *constraint, int *field) { *constraint = CONSTRAIN_NONE; *field = controlPoint_Index() ; if (handle >= 0 && handle < controlPoint()->getSize() / 3) { Vec3f ret((Vec3f)controlPoint()->getValue(handle) / weight()->getValue(handle)); return ret; } else { return Vec3f(0.0f, 0.0f, 0.0f); } } void NodeNurbsTextureSurface::setHandle(MFVec3f *value, int handle, float newWeight, const Vec3f &newV, const Vec3f &oldV, bool already_changed) { bool changed = false; MFVec3f *newValue = (MFVec3f *) value->copy(); if (_scene->getXSymetricNurbsMode()) { float epsilon = TheApp->GetEpsilon(); int numPoints = newValue->getSize() / 3; for (int i = 0; i < numPoints; i++) { if (i != handle) { Vec3f vPoint = controlPoint()->getValue(i); float wPoint = weight()->getValue(i); float w = wPoint; if (wPoint != 0) vPoint = vPoint / wPoint; if (newWeight != 0) w = w / newWeight; if ( (fabs(vPoint.z - oldV.z) < epsilon) && (fabs(vPoint.y - oldV.y) < epsilon)) { if (fabs(vPoint.x + oldV.x) < epsilon) { changed = true; if (fabs(oldV.x) < epsilon) newValue->setValue(i * 3, 0); else newValue->setValue(i * 3, - newV.x * w); newValue->setValue(i * 3+1, newV.y * w); newValue->setValue(i * 3+2, newV.z * w); } else if (fabs(vPoint.x - oldV.x) < epsilon) { changed = true; if (fabs(oldV.x) < epsilon) newValue->setValue(i * 3, 0); else newValue->setValue(i * 3, newV.x * w); newValue->setValue(i * 3+1, newV.y * w); newValue->setValue(i * 3+2, newV.z * w); } } } } } if (already_changed) changed = true; if (changed) { _scene->setField(this, controlPoint_Index(), newValue); } } void NodeNurbsTextureSurface::setHandle(float newWeight, const Vec3f &newV, const Vec3f &oldV) { setHandle(controlPoint(), -1, newWeight, newV, oldV); } NodeNurbsGroup * NodeNurbsTextureSurface::findNurbsGroup() { if (hasParent()) { Node* parent = getParent(); if (parent->getType() == NODE_NURBS_GROUP) { return (NodeNurbsGroup *) parent; } else if (parent->getType() == NODE_SHAPE) if (parent->hasParent()) if (parent->getParent()->getType() == NODE_NURBS_GROUP) { return (NodeNurbsGroup *) parent->getParent(); } } return NULL; } void NodeNurbsTextureSurface::setHandle(int handle, const Vec3f &v) { MFVec3f *newValue = new MFVec3f(*controlPoint()); float epsilon = TheApp->GetEpsilon(); int numPoints = controlPoint()->getSize() / 3; if (handle >= 0 && handle < numPoints) { float w = weight()->getValue(handle); Vec3f oldV = controlPoint()->getValue(handle); if (w != 0) oldV = oldV / w; Vec3f newV = v * w; if (_scene->getXSymetricNurbsMode() && (fabs(oldV.x) < epsilon)) newValue->setValue(handle * 3, 0); else newValue->setValue(handle * 3, newV.x); newValue->setValue(handle * 3+1, newV.y); newValue->setValue(handle * 3+2, newV.z); // set other handles for symetric modelling // which also snap handles at the same place setHandle(newValue, handle, w, newV, oldV, true); // search for NurbsGroup nodes and set handles if (_scene->getXSymetricNurbsMode()) { NodeNurbsGroup *nurbsGroup = findNurbsGroup(); if (nurbsGroup) nurbsGroup->setHandle(this, w, newV, oldV); } } } void NodeNurbsTextureSurface::setField(int index, FieldValue *value) { Node::setField(index, value); } bool NodeNurbsTextureSurface::writeEXTERNPROTO(int f) { RET_ONERROR( mywritestr(f ,"EXTERNPROTO NurbsTextureSurface[\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," field SFInt32 uDimension\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," field SFInt32 vDimension\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," field MFFloat uKnot\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," field MFFloat vKnot\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," field SFInt32 uOrder\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," field SFInt32 vOrder\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField MFVec3f controlPoint\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField MFFloat weight\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 ," \"urn:web3d:vrml97:node:NurbsTextureSurface\",\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," \"urn:inet:blaxxun.com:node:NurbsTextureSurface\",\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," \"urn:ParaGraph:NurbsTextureSurface\",\n") ) TheApp->incSelectionLinenumber(); #ifdef HAVE_VRML97_AMENDMENT1_PROTO_URL RET_ONERROR( mywritestr(f ," \"") ) RET_ONERROR( mywritestr(f ,HAVE_VRML97_AMENDMENT1_PROTO_URL) ) RET_ONERROR( mywritestr(f ,"/NurbsTextureSurfacePROTO.wrl") ) RET_ONERROR( mywritestr(f ,"\"\n") ) TheApp->incSelectionLinenumber(); #else RET_ONERROR( mywritestr(f ," \"NurbsTextureSurfacePROTO.wrl\",\n") ) TheApp->incSelectionLinenumber(); #endif RET_ONERROR( mywritestr(f ," \"http://www.csv.ica.uni-stuttgart.de/vrml/dune/docs/vrml97Amendment1/NurbsTextureSurfacePROTO.wrl\"\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ,"]\n") ) TheApp->incSelectionLinenumber(); return true; } int NodeNurbsTextureSurface::write(int filedes, int indent) { if (_scene->isPureVRML97()) { Node * node = toIndexedFaceSet(); RET_ONERROR( node->write(filedes, indent) ) node->unref(); } else RET_ONERROR( NodeData::write(filedes, indent) ) return 0; } void NodeNurbsTextureSurface::flip(int index) { if (controlPoint()) controlPoint()->flip(index); } Node* NodeNurbsTextureSurface::degreeElevate(int newUDegree, int newVDegree) { //degree elevate a nurbs surface, if(newUDegree < ((uOrder()->getValue())-1)){ return NULL; } if(newVDegree < ((vOrder()->getValue())-1)){ return NULL; } NodeNurbsTextureSurface *node = (NodeNurbsTextureSurface *) _scene->createNode("NurbsTextureSurface"); if((newUDegree >= ((uOrder()->getValue())-1)) && (newVDegree >= ((vOrder()->getValue())-1))){ //load old values int i; int tuDimension = uDimension()->getValue(); int tvDimension = vDimension()->getValue(); Vec3f *tPoints = new Vec3f[tuDimension * tvDimension]; float *tWeights = new float[tuDimension * tvDimension]; int tuOrder = uOrder()->getValue(); int tvOrder = vOrder()->getValue(); int uKnotSize = uKnot()->getSize(); int vKnotSize = vKnot()->getSize(); Array tuKnots(uKnotSize); Array tvKnots(vKnotSize); int tuDegree = tuOrder - 1; int tvDegree = tvOrder - 1; int tuUpDegree = newUDegree - tuDegree; int tvUpDegree = newVDegree - tvDegree; for (i=0; i<(tuDimension*tvDimension); i++){ tPoints[i] = controlPoint()->getValue(i); tWeights[i] =weight()->getValue(i); } for (i=0; igetValue(i); } for (i=0; igetValue(i); } //elevate surface NurbsSurfaceDegreeElevate elevatedSurface(tPoints, tWeights, tuKnots, tvKnots, tuDimension, tvDimension, tuDegree, tvDegree, tuUpDegree, tvUpDegree); //load new node int newUDimension = elevatedSurface.getUDimension(); int newVDimension = elevatedSurface.getVDimension(); float *newControlPoints = new float[newUDimension * newVDimension *3]; float *newWeights = new float[newUDimension * newVDimension]; float *newUKnots = new float[elevatedSurface.getUKnotSize()]; float *newVKnots = new float[elevatedSurface.getVKnotSize()]; int newUOrder = newUDegree + 1; int newVOrder = newVDegree + 1; for(i=0; i<(newUDimension * newVDimension); i++){ newControlPoints[(i*3)] = elevatedSurface.getControlPoints(i).x; newControlPoints[(i*3)+1] = elevatedSurface.getControlPoints(i).y; newControlPoints[(i*3)+2] = elevatedSurface.getControlPoints(i).z; newWeights[i] = elevatedSurface.getWeights(i); } for(i=0; i<(elevatedSurface.getUKnotSize()); i++){ newUKnots[i] = elevatedSurface.getUKnots(i); } for(i=0; i<(elevatedSurface.getVKnotSize()); i++){ newVKnots[i] = elevatedSurface.getVKnots(i); } node->setField(node->uDimension_Index(), new SFInt32(newUDimension)); node->setField(node->vDimension_Index(), new SFInt32(newVDimension)); node->uKnot(new MFFloat(newUKnots, newUDimension + newUOrder)); node->vKnot(new MFFloat(newVKnots, newVDimension + newVOrder)); node->setField(node->uOrder_Index(), new SFInt32(newUOrder)); node->setField(node->vOrder_Index(), new SFInt32(newVOrder)); node->controlPoint(new MFVec3f(newControlPoints, newUDimension * newVDimension * 3)); node->weight(new MFFloat(newWeights, newUDimension * newVDimension)); node->uTessellation(new SFInt32(uTessellation()->getValue())); node->vTessellation(new SFInt32(vTessellation()->getValue())); return node; } return NULL; }