|
|
878d83 |
|
|
|
878d83 |
#define HMAP_SIZE 1024
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
typedef struct {
|
|
|
878d83 |
double x, y, z;
|
|
|
878d83 |
double nx, ny, nz;
|
|
|
878d83 |
} Vertex;
|
|
|
878d83 |
|
|
|
878d83 |
typedef struct {
|
|
|
878d83 |
double (*map)[HMAP_SIZE];
|
|
|
878d83 |
double (*old)[HMAP_SIZE];
|
|
|
878d83 |
double maps[2][HMAP_SIZE][HMAP_SIZE];
|
|
|
878d83 |
double normals[HMAP_SIZE][HMAP_SIZE][3];
|
|
|
878d83 |
double stepXY;
|
|
|
878d83 |
double stepZ;
|
|
|
878d83 |
double color[4];
|
|
|
878d83 |
GLuint buf;
|
|
|
878d83 |
int bufCount;
|
|
|
878d83 |
} HMap;
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
void hmapInit(HMap *hmap, double stepXY, double stepZ, double r, double g, double b, double a) {
|
|
|
878d83 |
hmap->map = hmap->maps[0];
|
|
|
878d83 |
hmap->old = hmap->maps[1];
|
|
|
878d83 |
for(int i = 0; i < HMAP_SIZE; ++i) {
|
|
|
878d83 |
for(int j = 0; j < HMAP_SIZE; ++j) {
|
|
|
878d83 |
hmap->map[i][j] = 0;
|
|
|
878d83 |
hmap->old[i][j] = 0;
|
|
|
878d83 |
hmap->normals[i][j][0] = 0;
|
|
|
878d83 |
hmap->normals[i][j][1] = 0;
|
|
|
878d83 |
hmap->normals[i][j][2] = 0;
|
|
|
878d83 |
}
|
|
|
878d83 |
}
|
|
|
878d83 |
hmap->stepXY = stepXY;
|
|
|
878d83 |
hmap->stepZ = stepZ;
|
|
|
878d83 |
hmap->color[0] = r;
|
|
|
878d83 |
hmap->color[1] = g;
|
|
|
878d83 |
hmap->color[2] = b;
|
|
|
878d83 |
hmap->color[3] = a;
|
|
|
878d83 |
|
|
|
878d83 |
hmap->buf = 0;
|
|
|
878d83 |
hmap->bufCount = 0;
|
|
|
878d83 |
glGenBuffers(1, &hmap->buf);
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
void hmapDeinit(HMap *hmap) {
|
|
|
878d83 |
glDeleteBuffers(1, &hmap->buf);
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
void hmapSwap(HMap *hmap) {
|
|
|
878d83 |
double (*m)[HMAP_SIZE] = hmap->map;
|
|
|
878d83 |
hmap->map = hmap->old;
|
|
|
878d83 |
hmap->old = m;
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
void hmapCopy(HMap *hmap) {
|
|
|
878d83 |
for(int i = 0; i < HMAP_SIZE; ++i)
|
|
|
878d83 |
for(int j = 0; j < HMAP_SIZE; ++j)
|
|
|
878d83 |
hmap->old[i][j] = hmap->map[i][j];
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
void hmapGetVertex(const HMap *hmap, int i, int j, Vertex *v) {
|
|
|
878d83 |
int ii = (i%HMAP_SIZE + HMAP_SIZE)%HMAP_SIZE;
|
|
|
878d83 |
int jj = (j%HMAP_SIZE + HMAP_SIZE)%HMAP_SIZE;
|
|
|
878d83 |
v->x = hmap->stepXY*(i - 0.5*HMAP_SIZE);
|
|
|
878d83 |
v->y = hmap->stepXY*(j - 0.5*HMAP_SIZE);
|
|
|
878d83 |
v->z = hmap->stepZ*hmap->map[ii][jj];
|
|
|
878d83 |
v->nx = hmap->normals[ii][jj][0];
|
|
|
878d83 |
v->ny = hmap->normals[ii][jj][1];
|
|
|
878d83 |
v->nz = hmap->normals[ii][jj][2];
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
void hmapBuildBuf(HMap *hmap) {
|
|
|
878d83 |
static Vertex buf[ (HMAP_SIZE*2 + 4)*HMAP_SIZE*10 ];
|
|
|
878d83 |
Vertex *v = buf;
|
|
|
878d83 |
for(int j = 0; j < HMAP_SIZE; ++j) {
|
|
|
878d83 |
hmapGetVertex(hmap, 0, j, v++);
|
|
|
878d83 |
for(int i = 0; i <= HMAP_SIZE; ++i) {
|
|
|
878d83 |
hmapGetVertex(hmap, i, j, v++);
|
|
|
878d83 |
hmapGetVertex(hmap, i, j+1, v++);
|
|
|
878d83 |
}
|
|
|
878d83 |
hmapGetVertex(hmap, HMAP_SIZE, j+1, v++);
|
|
|
878d83 |
}
|
|
|
878d83 |
hmap->bufCount = v - buf;
|
|
|
878d83 |
|
|
|
878d83 |
glBindBuffer(GL_ARRAY_BUFFER, hmap->buf);
|
|
|
878d83 |
glBufferData(GL_ARRAY_BUFFER, hmap->bufCount*sizeof(*v), buf, GL_STATIC_DRAW);
|
|
|
878d83 |
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
void hmapDraw(const HMap *hmap) {
|
|
|
878d83 |
glColor4dv(hmap->color);
|
|
|
878d83 |
|
|
|
878d83 |
glBindBuffer(GL_ARRAY_BUFFER, hmap->buf);
|
|
|
878d83 |
glEnableClientState(GL_VERTEX_ARRAY);
|
|
|
878d83 |
glEnableClientState(GL_NORMAL_ARRAY);
|
|
|
878d83 |
glVertexPointer(3, GL_DOUBLE, sizeof(Vertex), (const void*)offsetof(Vertex, x));
|
|
|
878d83 |
glNormalPointer(GL_DOUBLE, sizeof(Vertex), (const void*)offsetof(Vertex, nx));
|
|
|
878d83 |
|
|
|
878d83 |
glDrawArrays(GL_TRIANGLE_STRIP, 0, hmap->bufCount);
|
|
|
878d83 |
|
|
|
878d83 |
glDisableClientState(GL_VERTEX_ARRAY);
|
|
|
878d83 |
glDisableClientState(GL_NORMAL_ARRAY);
|
|
|
878d83 |
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
878d83 |
|
|
|
878d83 |
glColor4d(1, 1, 1, 1);
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
void hmapDrawWrap(const HMap *hmap) {
|
|
|
878d83 |
for(int i = -1; i <= 1; ++i) {
|
|
|
878d83 |
for(int j = -1; j <= 1; ++j) {
|
|
|
878d83 |
glPushMatrix();
|
|
|
878d83 |
glTranslated(HMAP_SIZE*i*hmap->stepXY, HMAP_SIZE*j*hmap->stepXY, 0);
|
|
|
878d83 |
hmapDraw(hmap);
|
|
|
878d83 |
glPopMatrix();
|
|
|
878d83 |
}
|
|
|
878d83 |
}
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
double hmapGet(const HMap *hmap, int i, int j) {
|
|
|
878d83 |
i = (i%HMAP_SIZE + HMAP_SIZE)%HMAP_SIZE;
|
|
|
878d83 |
j = (j%HMAP_SIZE + HMAP_SIZE)%HMAP_SIZE;
|
|
|
878d83 |
return hmap->map[i][j];
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
void hmapCalcNormals(HMap *hmap) {
|
|
|
878d83 |
double dxy2 = 4 * hmap->stepXY * hmap->stepXY;
|
|
|
878d83 |
for(int i = 0; i < HMAP_SIZE; ++i) {
|
|
|
878d83 |
for(int j = 0; j < HMAP_SIZE; ++j) {
|
|
|
878d83 |
double dzx = (hmapGet(hmap, i+1, j) - hmapGet(hmap, i-1, j))*hmap->stepZ;
|
|
|
878d83 |
double k = 1/sqrt(dzx*dzx + dxy2);
|
|
|
878d83 |
double nz = dxy2*k;
|
|
|
878d83 |
double nx = -dzx*k;
|
|
|
878d83 |
|
|
|
878d83 |
double dzy = (hmapGet(hmap, i, j+1) - hmapGet(hmap, i, j-1))*hmap->stepZ;
|
|
|
878d83 |
k = 1/sqrt(dzy*dzy + dxy2);
|
|
|
878d83 |
nz += dxy2*k;
|
|
|
878d83 |
double ny = -dzy*k;
|
|
|
878d83 |
|
|
|
878d83 |
k = 1/sqrt(nx*nx + ny*ny + nz*nz);
|
|
|
878d83 |
hmap->normals[i][j][0] = nx*k;
|
|
|
878d83 |
hmap->normals[i][j][1] = ny*k;
|
|
|
878d83 |
hmap->normals[i][j][2] = nz*k;
|
|
|
878d83 |
}
|
|
|
878d83 |
}
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
double cubicInterpolation(double x0, double x1, double x2, double x3, float l) {
|
|
|
878d83 |
double a = x3 - x2 + x1 - x0;
|
|
|
878d83 |
double b = x0 - x1 - a;
|
|
|
878d83 |
double c = x2 - x0;
|
|
|
878d83 |
double d = x1;
|
|
|
878d83 |
return ((a*l + b)*l + c)*l + d;
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
double hmapGetBicubic(HMap *hmap, double x, double y, int step) {
|
|
|
878d83 |
x /= step;
|
|
|
878d83 |
y /= step;
|
|
|
878d83 |
int i0 = (int)floor(x);
|
|
|
878d83 |
int j0 = (int)floor(y);
|
|
|
878d83 |
double dx = x - i0;
|
|
|
878d83 |
double dy = y - j0;
|
|
|
878d83 |
|
|
|
878d83 |
double m[4][4];
|
|
|
878d83 |
for(int i = 0; i < 4; ++i)
|
|
|
878d83 |
for(int j = 0; j < 4; ++j)
|
|
|
878d83 |
m[i][j]= hmapGet(hmap, (i0 + i - 1)*step, (j0 + j - 1)*step);
|
|
|
878d83 |
|
|
|
878d83 |
return cubicInterpolation(
|
|
|
878d83 |
cubicInterpolation(m[0][0], m[1][0], m[2][0], m[3][0], dx),
|
|
|
878d83 |
cubicInterpolation(m[0][1], m[1][1], m[2][1], m[3][1], dx),
|
|
|
878d83 |
cubicInterpolation(m[0][2], m[1][2], m[2][2], m[3][2], dx),
|
|
|
878d83 |
cubicInterpolation(m[0][3], m[1][3], m[2][3], m[3][3], dx),
|
|
|
878d83 |
dy );
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
|
|
|
878d83 |
void hmapGenerate(HMap *hmap) {
|
|
|
878d83 |
const int maxStep = HMAP_SIZE/2;
|
|
|
878d83 |
const int minStep = 1;
|
|
|
878d83 |
const double maxFactor = 0.25*maxStep;
|
|
|
878d83 |
|
|
|
878d83 |
for(int i = 0; i < HMAP_SIZE; i += maxStep)
|
|
|
878d83 |
for(int j = 0; j < HMAP_SIZE; j += maxStep)
|
|
|
878d83 |
hmap->map[i][j] = (randomFloat() - 0.5)*2*maxFactor;
|
|
|
878d83 |
|
|
|
878d83 |
double factor = 0.5*maxFactor;
|
|
|
878d83 |
for(int step = maxStep/2; step >= minStep; step /= 2, factor /= 2) {
|
|
|
878d83 |
for(int i = step; i < HMAP_SIZE; i += 2*step)
|
|
|
878d83 |
for(int j = step; j < HMAP_SIZE; j += 2*step)
|
|
|
878d83 |
hmap->map[i][j] = ( hmapGet(hmap, i - step, j - step)
|
|
|
878d83 |
+ hmapGet(hmap, i + step, j - step)
|
|
|
878d83 |
+ hmapGet(hmap, i - step, j + step)
|
|
|
878d83 |
+ hmapGet(hmap, i + step, j + step) )*0.25
|
|
|
878d83 |
+ (randomFloat() - 0.5)*2*factor;
|
|
|
878d83 |
for(int i = 0; i < HMAP_SIZE; i += step)
|
|
|
878d83 |
for(int j = step*(1 - i/step%2); j < HMAP_SIZE; j += 2*step)
|
|
|
878d83 |
hmap->map[i][j] = ( hmapGet(hmap, i - step, j)
|
|
|
878d83 |
+ hmapGet(hmap, i + step, j)
|
|
|
878d83 |
+ hmapGet(hmap, i, j - step)
|
|
|
878d83 |
+ hmapGet(hmap, i, j + step) )*0.25
|
|
|
878d83 |
+ (randomFloat() - 0.5)*2*factor;
|
|
|
878d83 |
}
|
|
|
878d83 |
|
|
|
878d83 |
if (minStep > 1)
|
|
|
878d83 |
for(int i = 0; i < HMAP_SIZE; ++i)
|
|
|
878d83 |
for(int j = 0; j < HMAP_SIZE; ++j)
|
|
|
878d83 |
if (i % minStep || j % minStep)
|
|
|
878d83 |
hmap->map[i][j] = hmapGetBicubic(hmap, i, j, minStep);
|
|
|
878d83 |
|
|
|
878d83 |
hmapCalcNormals(hmap);
|
|
|
878d83 |
}
|
|
|
878d83 |
|