00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "heightfield.h"
00025 #include "paramset.h"
00026
00027 using namespace lux;
00028
00029
00030 Heightfield::Heightfield(const Transform &o2w, bool ro, int x, int y,
00031 const float *zs)
00032 : Shape(o2w, ro) {
00033 nx = x;
00034 ny = y;
00035 z = new float[nx*ny];
00036 memcpy(z, zs, nx*ny*sizeof(float));
00037 }
00038 Heightfield::~Heightfield() {
00039 delete[] z;
00040 }
00041 BBox Heightfield::ObjectBound() const {
00042 float minz = z[0], maxz = z[0];
00043 for (int i = 1; i < nx*ny; ++i) {
00044 if (z[i] < minz) minz = z[i];
00045 if (z[i] > maxz) maxz = z[i];
00046 }
00047 return BBox(Point(0,0,minz), Point(1,1,maxz));
00048 }
00049 bool Heightfield::CanIntersect() const {
00050 return false;
00051 }
00052 void Heightfield::Refine(vector<boost::shared_ptr<Shape> > &refined) const {
00053 int ntris = 2*(nx-1)*(ny-1);
00054 refined.reserve(ntris);
00055 int *verts = new int[3*ntris];
00056 Point *P = new Point[nx*ny];
00057 float *uvs = new float[2*nx*ny];
00058 int nverts = nx*ny;
00059 int x, y;
00060
00061 int pos = 0;
00062 for (y = 0; y < ny; ++y) {
00063 for (x = 0; x < nx; ++x) {
00064 P[pos].x = uvs[2*pos] = (float)x / (float)(nx-1);
00065 P[pos].y = uvs[2*pos+1] = (float)y / (float)(ny-1);
00066 P[pos].z = z[pos];
00067 ++pos;
00068 }
00069 }
00070
00071 int *vp = verts;
00072 for (y = 0; y < ny-1; ++y) {
00073 for (x = 0; x < nx-1; ++x) {
00074 #define VERT(x,y) ((x)+(y)*nx)
00075 *vp++ = VERT(x, y);
00076 *vp++ = VERT(x+1, y);
00077 *vp++ = VERT(x+1, y+1);
00078
00079 *vp++ = VERT(x, y);
00080 *vp++ = VERT(x+1, y+1);
00081 *vp++ = VERT(x, y+1);
00082 }
00083 #undef VERT
00084 }
00085 ParamSet paramSet;
00086 paramSet.AddInt("indices", verts, 3*ntris);
00087 paramSet.AddFloat("uv", uvs, 2 * nverts);
00088 paramSet.AddPoint("P", P, nverts);
00089 refined.push_back(MakeShape("trianglemesh",
00090 ObjectToWorld, reverseOrientation, paramSet));
00091 delete[] P;
00092 delete[] uvs;
00093 delete[] verts;
00094 }
00095 Shape* Heightfield::CreateShape(const Transform &o2w,
00096 bool reverseOrientation, const ParamSet ¶ms) {
00097 int nu = params.FindOneInt("nu", -1);
00098 int nv = params.FindOneInt("nv", -1);
00099 int nitems;
00100 const float *Pz = params.FindFloat("Pz", &nitems);
00101 BOOST_ASSERT(nitems == nu*nv);
00102 BOOST_ASSERT(nu != -1 && nv != -1 && Pz != NULL);
00103 return new Heightfield(o2w, reverseOrientation, nu, nv, Pz);
00104 }