/* * NodeElevationGrid.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 "stdafx.h" #include "NodeElevationGrid.h" #include "MFColor.h" #include "MFFloat.h" #include "MFInt32.h" #include "MFVec2f.h" #include "MFVec3f.h" #include "SFBool.h" #include "SFFloat.h" #include "SFInt32.h" #include "SFNode.h" #include "Scene.h" #include "Mesh.h" #include "RenderState.h" #include "NodeNormal.h" #include "NodeColor.h" #include "NodeTextureCoordinate.h" #include "Util.h" #include "Field.h" ProtoElevationGrid::ProtoElevationGrid(Scene *scene) : Proto(scene, "ElevationGrid") { color.set( addExposedField(SFNODE, "color", new SFNode(NULL), NODE_COLOR)); normal.set( addExposedField(SFNODE, "normal", new SFNode(NULL), NODE_NORMAL)); texCoord.set( addExposedField(SFNODE, "texCoord", new SFNode(NULL), TEXTURE_COORDINATE_NODE)); height.set( addField(MFFLOAT, "height", new MFFloat())); ccw.set( addField(SFBOOL, "ccw", new SFBool(true))); colorPerVertex.set( addField(SFBOOL, "colorPerVertex", new SFBool(true))); creaseAngle.set( addField(SFFLOAT, "creaseAngle", new SFFloat(0.0f), new SFFloat(0.0f))); normalPerVertex.set( addField(SFBOOL, "normalPerVertex", new SFBool(true))); solid.set( addField(SFBOOL, "solid", new SFBool(true))); xDimension.set( addField(SFINT32, "xDimension", new SFInt32(0), new SFInt32(0))); xSpacing.set( addField(SFFLOAT, "xSpacing", new SFFloat(1.0f), new SFInt32(0))); zDimension.set( addField(SFINT32, "zDimension", new SFInt32(0), new SFInt32(0))); zSpacing.set( addField(SFFLOAT, "zSpacing", new SFFloat(1.0f), new SFInt32(0))); addEventIn(MFFLOAT, "set_height", EIF_RECOMMENDED, height); } Node * ProtoElevationGrid::create(Scene *scene) { return new NodeElevationGrid(scene, this); } NodeElevationGrid::NodeElevationGrid(Scene *scene, Proto *def) : MeshBasedNode(scene, def) { } NodeElevationGrid::~NodeElevationGrid() { delete _mesh; } #define HEIGHT(i, j) (fheight[(i) + (j) * ixDimension]) void NodeElevationGrid::createMesh() { Node *color = ((SFNode *) getField(color_Index(),true))->getValue(); Node *normal = ((SFNode *) getField(normal_Index(),true))->getValue(); Node *texCoord = ((SFNode *) getField(texCoord_Index(),true))->getValue(); const float *fheight = ((MFFloat *) getField(height_Index()))->getValues(); // bool colorPerVertex = ((SFBool *) // getField(colorPerVertex_Index()))->getValue(); // bool normalPerVertex = ((SFBool *) // getField(normalPerVertex_Index()))->getValue(); int ixDimension = xDimension()->getValue(); int izDimension = zDimension()->getValue(); if (ixDimension == 0 || izDimension == 0) return; MFVec3f *normals = normal ? ((NodeNormal *)normal)->vector() : NULL; MFColor *colors = color ? ((NodeColor *)color)->color() : NULL; MFVec2f *texCoords = texCoord ? ((NodeTextureCoordinate *) texCoord)->point() : NULL; int size = ixDimension * izDimension; Vec3f *vertices = new Vec3f[size]; Vec2f *tc = new Vec2f[size]; int index = 0; int i, j; for (j = 0; j < izDimension; j++) { for (i = 0; i < ixDimension; i++) { vertices[index] = Vec3f(i * xSpacing()->getValue(), HEIGHT(i, j), j * zSpacing()->getValue()); tc[index] = Vec2f(i / (ixDimension-1.0f), j / (izDimension-1.0f)); index++; } } index = 0; int *ci = new int[size * 8]; for (j = 0; j < izDimension-1; j++) { for (i = 0; i < ixDimension-1; i++) { ci[index++] = j * ixDimension + i; ci[index++] = (j+1) * ixDimension + (i+1); ci[index++] = j * ixDimension + (i+1); ci[index++] = -1; ci[index++] = j * ixDimension + i; ci[index++] = (j+1) * ixDimension + i; ci[index++] = (j+1) * ixDimension + (i+1); ci[index++] = -1; } } MFVec3f *v = new MFVec3f((float *) vertices, size * 3); MFInt32 *coordIndex = new MFInt32(ci, index); if (!texCoords) texCoords = new MFVec2f((float *) tc, size * 2); int meshFlags = 0; if (ccw()->getValue()) meshFlags |= MESH_CCW; if (solid()->getValue()) meshFlags |= MESH_SOLID; if (_mesh) delete _mesh; _mesh = new Mesh(v, coordIndex, normals, NULL, colors, NULL, texCoords, NULL, creaseAngle()->getValue(), meshFlags); } void NodeElevationGrid::drawHandles() { const float *fheight = height()->getValues(); int ixDimension = xDimension()->getValue(); int izDimension = zDimension()->getValue(); RenderState state; if (ixDimension < 2 || izDimension < 2) return; if (height()->getSize() != ixDimension * izDimension) return; glDisable(GL_LIGHTING); glPushName(0); Util::myGlColor3f(1.0f, 1.0f, 1.0f); state.startDrawHandles(); for (int j = 0; j < izDimension; j++) { for (int i = 0; i < ixDimension; i++) { glLoadName(j * ixDimension + i); state.drawHandle(Vec3f(i * xSpacing()->getValue(), HEIGHT(i, j), j * zSpacing()->getValue())); } } state.endDrawHandles(); glPopName(); glEnable(GL_LIGHTING); } void NodeElevationGrid::setField(int index, FieldValue *value) { _meshDirty = true; Node::setField(index, value); } Vec3f NodeElevationGrid::getHandle(int handle, int *constraint, int *field) { int ixDimension = xDimension()->getValue(); const float *fheight = height()->getValues(); float x = (handle % ixDimension) * xSpacing()->getValue(); float y = fheight[handle]; float z = handle / ixDimension * zSpacing()->getValue(); *field = 3; *constraint = CONSTRAIN_Y; return Vec3f(x, y, z); } void NodeElevationGrid::setHandle(int handle, const Vec3f &v) { MFFloat *oldValue = (MFFloat *) getField(height_Index()); MFFloat *newValue = (MFFloat *) oldValue->copy(); newValue->setValue(handle, v.y); _scene->setField(this, height_Index(), newValue); }