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