infinite terrain experiments
[shady.git] / terrain.cpp
blob479c00286b671b8abaf75272fe36ee5fab53eb07
2 #include "terrain.hpp"
3 #include "transform.hpp"
4 #include "renderer.hpp"
5 extern "C" {
6 #include <GL/glew.h>
7 #include <GL/gl.h>
10 #include <iostream>
11 #include <cstdlib>
12 #include <cmath>
13 #include <boost-1_46/boost/config/no_tr1/complex.hpp>
14 using std::cout;
15 using std::endl;
17 float randdiff(float scale,float power) {
18 float tmp = ((float)rand())/RAND_MAX; //value between 0 and 1
19 //cerr << "in: " << tmp <<"\n";
20 tmp = (tmp*2-1); // between -1 and 1
21 bool neg = false;
22 if(tmp < 0) {
23 neg = true;
24 tmp *= -1;
26 tmp = pow(tmp, power);
27 if(neg) {
28 tmp *=-1;
30 //cerr << "out: " << tmp <<"\n";
31 return tmp*scale;
34 int mod(int a, int b) {
35 int v = a;
36 if(v < 0) {
37 v = b - a;
39 return v % b;
42 terrain::terrain(int res, float size, float height) : vertices(NULL) {
43 this->res = res;
44 this->height = height;
45 this->size = size;
47 // cout << "allocating trrn ram size:" << res*res*sizeof(float) << endl;
48 // allocate RAM
49 data = new float*[res];
50 for(int x = 0; x < res; x++) {
51 data[x] = new float[res];
52 for(int y = 0; y < res; y++) {
53 data[x][y] = 0;
56 // cout << "done allocating" << endl;
59 terrain::~terrain() {
60 //free RAM
61 for(int i = 0; i < res; i++) {
62 delete data[i];
64 delete data;
67 void terrain::generate(int randres, float divisor, float power, int seed){
68 srand(seed);
69 cout << "generating trrn map" << endl;
70 //clear map
71 for(int x = 0; x < res; x++) for(int y = 0; y < res; y++){
72 data[x][y] = 0;
75 //initialize randres with random values
76 for(int x = 0; x < res; x += res/randres) for(int y = 0; y < res; y += res/randres) {
77 data[x][y] = 0.5 + randdiff(0.3, power);
80 float coef = .3;
81 int s;
82 for(int level = randres; level < res; level *= 2) {
83 s = res/level/2;
84 coef /= divisor;
85 //diamond
86 for(int x = res/(2*level); x < res; x += res/level) for(int y = res/(2*level); y < res; y += res/level) {
87 data[x][y] =
88 (data[mod(x+s, res)][mod(y+s, res)]
89 + data[mod(x+s, res)][mod(y-s, res)]
90 + data[mod(x-s, res)][mod(y+s, res)]
91 + data[mod(x-s, res)][mod(y-s, res)]) / 4
92 + randdiff(coef,power);
94 coef /= divisor;
95 //square
96 for(int x = 0; x < res; x += res/(2*level)) for(int y = 0; y < res; y += res/(2*level))
97 if((x % (res/level)) ^ (y % (res/level))){
98 //cerr << "adding " << x << "x" << y << "\n";
99 data[x][y] =
100 (data[mod(x+s, res)][y]
101 + data[mod(x-s, res)][y]
102 + data[x][mod(y+s, res)]
103 + data[x][mod(y-s, res)]) / 4
104 + randdiff(coef, power);
108 cout << "done generating" << endl;
111 float terrain::xVal(int x, int y) const {
112 return (float)x * size / (float)res - size/2;
115 float terrain::yVal(int x, int y) const {
116 return height * data[mod(x, res)][mod(y, res)];
119 float terrain::zVal(int x, int y) const {
120 return (float)y * size / (float)res - size/2;
123 float interpolWeight(float x, float y) {
124 return std::sqrt((x * x) + (y * y)) + 0.00001;
127 float terrain::heightAt(float x, float y) const {
128 float a = (x + size/2) * (float)res / size;
129 float b = (y + size/2) * (float)res / size;
131 //rounded position
132 int ra = (int)a;
133 int rb = (int)b;
135 //differences
136 // TODO interpolate
137 float tmp;
138 tmp = yVal(ra, rb)*interpolWeight(ra-a,rb-b)
139 +yVal(ra+1, rb)*interpolWeight(ra+1-a,rb-b)
140 +yVal(ra, rb+1)*interpolWeight(ra-a,rb+1-b)
141 +yVal(ra+1, rb+1)*interpolWeight(ra-a,rb+1-b);
142 tmp /= interpolWeight(ra-a,rb-b)
143 +interpolWeight(ra+1-a,rb-b)
144 +interpolWeight(ra-a,rb+1-b)
145 +interpolWeight(ra-a,rb+1-b);
146 return tmp;
149 #define terrainindex(x, y) ((res * mod((y), res)) + mod((x), res))
151 void terrain::generateVertices() {
153 if(vertices) {
154 delete[] vertices;
156 vertices = new Vertex[res * res];
158 glBufferData(GL_ARRAY_BUFFER, res * res * sizeof(Vertex), NULL, GL_STATIC_DRAW);
160 Vertex * vert = reinterpret_cast<Vertex *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
162 for(int y = 0; y < res; y++) for(int x = 0; x < res; x++) {
164 vec rect[4] = {
165 vec(xVal(x+1, y-1), yVal(x+1, y-1), zVal(x+1, y-1)),
166 vec(xVal(x-1, y-1), yVal(x-1, y-1), zVal(x-1, y-1)),
167 vec(xVal(x-1, y+1), yVal(x-1, y+1), zVal(x-1, y+1)),
168 vec(xVal(x+1, y+1), yVal(x+1, y+1), zVal(x+1, y+1))
171 Vertex & v = vertices[terrainindex(x, y)];
173 v.pos = vec(xVal(x, y), yVal(x, y), zVal(x, y));
174 v.normal = calculateNormal(rect, 4);
176 vert[terrainindex(x, y)] = v;
179 glUnmapBuffer(GL_ARRAY_BUFFER);
181 checkGl("adding terrain vertices");
184 void terrain::setVertexArray(Vertex * vert) {
186 glEnableClientState(GL_VERTEX_ARRAY);
187 glEnableClientState(GL_NORMAL_ARRAY);
189 glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &vert->pos);
190 glNormalPointer(GL_FLOAT, sizeof(Vertex), &vert->normal);
194 bool terrain::isSubdivided(int x0, int x1, int y0, int y1, vec pos) const {
196 if(x1 - x0 <= 1 || y1 - y0 <= 1) {
197 return false;
200 int w = (x1 - x0), h = (y1 - y0);
201 int mx = ((w / 2) + x0), my = ((h / 2) + y0);
202 vec center(xVal(mx, my), yVal(mx, my), zVal(mx, my));
204 float sfacor = res / float(sqrt(w * h));
206 vec diff = (pos - center);
207 diff.y /= 2;
208 float d = diff.det();
209 if(d > 7.f) {
210 d -= 7.f;
211 } else {
212 d = 0.f;
215 return (d * sfacor < 300.f);
218 void terrain::addRect(std::vector<unsigned short> & ind, int x0, int x1, int y0, int y1, vec pos, ToCenter tc) const {
220 int w = (x1 - x0), h = (y1 - y0);
221 int mx = (x0 + (w/2)), my = (y0 + (h/2));
223 if(isSubdivided(x0, x1, y0, y1, pos)) {
225 // subdivide
227 addRect(ind, x0, mx, y0, my, pos, None);
228 addRect(ind, x0, mx, my, y1, pos, None);
229 addRect(ind, mx, x1, my, y1, pos, None);
230 addRect(ind, mx, x1, y0, my, pos, None);
232 } else {
234 GLbyte * c = reinterpret_cast<GLbyte *>(&data[mod(x0, res)][mod(y0, res)]);
235 glColor3f(float(c[0])/256 + .5f, float(c[1])/256 + .5f, float(c[2])/256 + .5f);
237 int tvert = 0;
238 tvert |= ((tc == X0) || isSubdivided(x0 - w, x0, y0, y1, pos)) ? X0 : 0;
239 tvert |= ((tc == X1) || isSubdivided(x1, x1 + w, y0, y1, pos)) ? X1 : 0;
240 tvert |= ((tc == Y0) || isSubdivided(x0, x1, y0 - h, y0, pos)) ? Y0 : 0;
241 tvert |= ((tc == Y1) || isSubdivided(x0, x1, y1, y1 + h, pos)) ? Y1 : 0;
243 switch(tvert) {
245 case 0: {
247 glBegin(GL_QUADS);
249 drawGlVertex(x0, y0);
250 drawGlVertex(x0, y1);
251 drawGlVertex(x1, y1);
252 drawGlVertex(x1, y0);
254 glEnd();
256 break;
259 case X0: {
261 glBegin(GL_TRIANGLES);
263 drawGlVertex(x1, y0);
264 drawGlVertex(x0, y0);
265 drawGlVertex(x0, my);
267 drawGlVertex(x0, my);
268 drawGlVertex(x1, y1);
269 drawGlVertex(x1, y0);
271 drawGlVertex(x0, my);
272 drawGlVertex(x0, y1);
273 drawGlVertex(x1, y1);
275 glEnd();
277 break;
280 case X0 | Y1: {
282 glColor3f(1.f, 1.f, 1.f);
284 glBegin(GL_TRIANGLES);
286 drawGlVertex(x0, my);
287 drawGlVertex(mx, y1);
288 drawGlVertex(x1, y0);
290 drawGlVertex(x0, my);
291 drawGlVertex(x0, y1);
292 drawGlVertex(mx, y1);
294 drawGlVertex(x1, y0);
295 drawGlVertex(mx, y1);
296 drawGlVertex(x1, y1);
298 drawGlVertex(x0, my);
299 drawGlVertex(x1, y0);
300 drawGlVertex(x0, y0);
302 glEnd();
304 break;
307 case X0 | Y0: {
309 glColor3f(1.f, 1.f, 1.f);
311 glBegin(GL_TRIANGLES);
313 drawGlVertex(x0, my);
314 drawGlVertex(x1, y1);
315 drawGlVertex(mx, y0);
317 drawGlVertex(x0, my);
318 drawGlVertex(mx, y0);
319 drawGlVertex(x0, y0);
321 drawGlVertex(x1, y1);
322 drawGlVertex(x1, y0);
323 drawGlVertex(mx, y0);
325 drawGlVertex(x0, my);
326 drawGlVertex(x0, y1);
327 drawGlVertex(x1, y1);
329 glEnd();
331 break;
334 case X0 | Y0 | Y1: {
337 break;
340 case X0 | X1: {
343 break;
347 case X0 | X1 | Y1: {
350 break;
353 case X0 | X1 | Y0: {
356 break;
359 case X0 | X1 | Y0 | Y1: {
362 break;
366 case X1: {
368 glBegin(GL_TRIANGLES);
370 drawGlVertex(x1, y0);
371 drawGlVertex(x0, y0);
372 drawGlVertex(x1, my);
374 drawGlVertex(x1, my);
375 drawGlVertex(x0, y0);
376 drawGlVertex(x0, y1);
378 drawGlVertex(x1, my);
379 drawGlVertex(x0, y1);
380 drawGlVertex(x1, y1);
382 glEnd();
385 break;
388 case X1 | Y1: {
390 glColor3f(1.f, 1.f, 1.f);
392 glBegin(GL_TRIANGLES);
394 drawGlVertex(x1, my);
395 drawGlVertex(x0, y0);
396 drawGlVertex(mx, y1);
398 drawGlVertex(x1, my);
399 drawGlVertex(mx, y1);
400 drawGlVertex(x1, y1);
402 drawGlVertex(x0, y0);
403 drawGlVertex(x0, y1);
404 drawGlVertex(mx, y1);
406 drawGlVertex(x1, my);
407 drawGlVertex(x1, y0);
408 drawGlVertex(x0, y0);
410 glEnd();
413 break;
416 case X1 | Y0: {
418 glColor3f(1.f, 1.f, 1.f);
420 glBegin(GL_TRIANGLES);
422 drawGlVertex(x1, my);
423 drawGlVertex(mx, y0);
424 drawGlVertex(x0, y1);
426 drawGlVertex(x1, my);
427 drawGlVertex(x1, y0);
428 drawGlVertex(mx, y0);
430 drawGlVertex(x0, y1);
431 drawGlVertex(mx, y0);
432 drawGlVertex(x0, y0);
434 drawGlVertex(x1, my);
435 drawGlVertex(x0, y1);
436 drawGlVertex(x1, y1);
438 glEnd();
441 break;
444 case X1 | Y0 | Y1: {
447 break;
450 case Y0: {
452 glBegin(GL_TRIANGLES);
454 drawGlVertex(x0, y0);
455 drawGlVertex(x0, y1);
456 drawGlVertex(mx, y0);
458 drawGlVertex(mx, y0);
459 drawGlVertex(x0, y1);
460 drawGlVertex(x1, y1);
462 drawGlVertex(mx, y0);
463 drawGlVertex(x1, y1);
464 drawGlVertex(x1, y0);
466 glEnd();
469 break;
472 case Y0 | Y1: {
475 break;
478 case Y1: {
480 glBegin(GL_TRIANGLES);
482 drawGlVertex(x0, y0);
483 drawGlVertex(x0, y1);
484 drawGlVertex(mx, y1);
486 drawGlVertex(mx, y1);
487 drawGlVertex(x1, y0);
488 drawGlVertex(x0, y0);
490 drawGlVertex(mx, y1);
491 drawGlVertex(x1, y1);
492 drawGlVertex(x1, y0);
494 glEnd();
497 break;
504 ind.push_back(terrainindex(x0, y0));
505 ind.push_back(terrainindex(x0, y1));
506 ind.push_back(terrainindex(x1, y1));
507 ind.push_back(terrainindex(x1, y0));*/
514 void terrain::drawVertices(vec pos) const {
516 glDisable(GL_LINE_SMOOTH);
517 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
519 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
521 glLineWidth(.5f);
523 std::vector<unsigned short> indices;
525 indices.reserve(1000);
527 // rounded position
528 float a = (pos.x + size/2) * (float)res / size;
529 float b = (pos.z + size/2) * (float)res / size;
530 int ix = int(a + .5f), iy = int(b + .5f);
532 int depth = abs(heightAt(pos.x, pos.z) - pos.y);
533 if(depth < 1) {
534 depth = 1;
536 size_t r = 2 << (size_t)log(depth * 2);
538 addRect(indices, ix - r, ix, iy - r, iy , pos, None);
539 addRect(indices, ix, ix + r, iy - r, iy , pos, None);
540 addRect(indices, ix, ix + r, iy, iy + r, pos, None);
541 addRect(indices, ix - r, ix, iy, iy + r, pos, None);
543 for(int i = 0; indices.size() < 750 && i < 20; r *= 2, i++) {
545 size_t r2 = r * 2;
547 addRect(indices, ix - r2, ix - r, iy - r2, iy - r, pos, None);
548 addRect(indices, ix - r, ix, iy - r2, iy - r, pos, i == 0 ? None : Y1);
549 addRect(indices, ix, ix + r, iy - r2, iy - r, pos, i == 0 ? None : Y1);
550 addRect(indices, ix + r, ix + r2, iy - r2, iy - r, pos, None);
551 addRect(indices, ix + r, ix + r2, iy - r, iy , pos, i == 0 ? None : X0);
552 addRect(indices, ix + r, ix + r2, iy, iy + r, pos, i == 0 ? None : X0);
553 addRect(indices, ix + r, ix + r2, iy + r, iy + r2, pos, None);
554 addRect(indices, ix, ix + r, iy + r, iy + r2, pos, i == 0 ? None : Y0);
555 addRect(indices, ix - r, ix, iy + r, iy + r2, pos, i == 0 ? None : Y0);
556 addRect(indices, ix - r2, ix - r, iy + r, iy + r2, pos, None);
557 addRect(indices, ix - r2, ix - r, iy, iy + r, pos, i == 0 ? None : X1);
558 addRect(indices, ix - r2, ix - r, iy - r, iy , pos, i == 0 ? None : X1);
562 // setVertexArray(NULL);
564 glColor3f(0.5, 0.4, 0.2);
566 //glDrawElements(GL_QUADS, indices.size(), GL_UNSIGNED_SHORT, &indices.front());
568 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
570 checkGl("rendering terrain vertices");
573 void terrain::drawGlVertex(int x, int y) const {
575 /*float nx = yVal(x-1,y) - yVal(x+1,y); //Height[x-1][y] - Height[x+1][y];
576 float nz = 4 / (size/res);
577 float ny = yVal(x,y-1) - yVal(x,y+1); //Height[x][y-1] - Height[x][y+1];*/
578 /*vec rect[4] = {
579 vec(xVal(x+1, y-1), yVal(x+1, y-1), zVal(x+1, y-1)),
580 vec(xVal(x-1, y-1), yVal(x-1, y-1), zVal(x-1, y-1)),
581 vec(xVal(x-1, y+1), yVal(x-1, y+1), zVal(x-1, y+1)),
582 vec(xVal(x+1, y+1), yVal(x+1, y+1), zVal(x+1, y+1))
583 };*/
586 //glColor3f(0.5, 0.4, 0.2);
587 //glColor3f(x / res + .1f, y / res + .1f, randVal() + .1f);
588 //vec normal = calculateNormal(rect,4);
589 const vec & normal = vertices[terrainindex(x, y)].normal;
590 glNormal3f(normal.x, normal.y, normal.z);
593 vec pos(xVal(x, y), yVal(x, y), zVal(x, y));
594 //const vec & pos = vertices[terrainindex(x, y)].pos;
595 glVertex3f(pos.x, pos.y, pos.z);
598 void terrain::drawGl() const {
599 glBegin(GL_QUADS);
600 for(int y = 0; y < res; y++) for(int x = 0; x < res; x++) {
601 drawGlVertex(x + 0, y + 0);
602 drawGlVertex(x + 0, y + 1);
603 drawGlVertex(x + 1, y + 1);
604 drawGlVertex(x + 1, y + 0);
606 glEnd();