Fixed normal calculation at edges, more UI changes
[ted.git] / src / terrain.c
blob084a6748d1a9986dafddd236b12c1ca791d3e636
1 #include "terrain.h"
2 #include <stdlib.h>
3 #include <math.h>
4 #include <string.h> // for memset
6 struct terrain* terrain_create(int size)
8 struct terrain *t = malloc(sizeof(struct terrain));
9 t->size = size;
10 t->height = malloc(sizeof(float)*size*size);
11 t->normal = malloc(sizeof(struct point)*size*size);
12 t->drawmode = FLAT;
13 t->drawlist = glGenLists(1);
14 t->dirty = 1;
15 t->max_height = 1.0;
16 return t;
19 void terrain_destroy(struct terrain* t)
21 free(t->height);
22 free(t->normal);
23 glDeleteLists(t->drawlist, 1);
24 free(t);
27 inline static void calculate_normal(int ai, int aj, int bi, int bj, int ci, int cj,
28 float *height, struct point *normal, int size)
30 struct point a = {ai, height[ai*size+aj], aj, 0.0};
31 struct point b = {bi, height[bi*size+bj], bj, 0.0};
32 struct point c = {ci, height[ci*size+cj], cj, 0.0};
34 b.x -= a.x;
35 b.y -= a.y;
36 b.z -= a.z;
38 c.x -= a.x;
39 c.y -= a.y;
40 c.z -= a.z;
42 struct point *n = &normal[ai*size+aj];
44 point_cross(n, &b, &c);
45 point_norm(n);
48 void terrain_bake(struct terrain *t)
50 int size = t->size;
51 float *height = t->height;
52 struct point *normal = t->normal;
53 struct point tmp, *ptr;
55 t->dirty = 1;
57 // calculate the inside
58 int i, j;
59 for (i=1; i<size-1; i++)
61 for (j=1; j<size-1; j++)
63 ptr = &normal[i*size+j];
64 calculate_normal(i,j, i,j+1, i+1,j, height, normal, size);
65 tmp.x = ptr->x;
66 tmp.y = ptr->y;
67 tmp.z = ptr->z;
68 calculate_normal(i,j, i+1,j, i,j-1, height, normal, size);
69 tmp.x += ptr->x;
70 tmp.y += ptr->y;
71 tmp.z += ptr->z;
72 calculate_normal(i,j, i,j-1, i-1,j, height, normal, size);
73 tmp.x += ptr->x;
74 tmp.y += ptr->y;
75 tmp.z += ptr->z;
76 calculate_normal(i,j, i-1,j, i,j+1, height, normal, size);
77 tmp.x += ptr->x;
78 tmp.y += ptr->y;
79 tmp.z += ptr->z;
81 tmp.x *= 0.25;
82 tmp.y *= 0.25;
83 tmp.z *= 0.25;
84 ptr->x = tmp.x;
85 ptr->y = tmp.y;
86 ptr->z = tmp.z;
90 // calculate the outer ridge
91 i=size-1;
92 for (j=0; j<size-1; j++)
94 calculate_normal(0,j, 0,j+1, 1,j, height, normal, size);
95 calculate_normal(i,j, i-1,j, i,j+1, height, normal, size);
96 calculate_normal(j,0, j,1, j+1,0, height, normal, size);
97 calculate_normal(j,i, j+1,i, j,i-1, height, normal, size);
101 void build_execute(struct terrain *t)
103 glNewList(t->drawlist, GL_COMPILE_AND_EXECUTE);
105 int size = t->size;
106 float *height = t->height;
107 struct point *normal = t->normal;
109 struct point *n;
110 float z, zcol;
112 float div = t->max_height - t->min_height;
113 if (div == 0) div = 0.000001;
114 float scale = 1.0/div;
116 int i, j;
117 for (i=0; i<size-1; i++)
119 glBegin(GL_TRIANGLE_STRIP);
120 for (j=0; j<size; j++)
122 z = height[i*size+j];
123 zcol = (z - t->min_height)*scale;
125 if (t->drawmode == FLAT)
126 glColor3f(0.0, zcol, 1.0 - zcol);
128 if (t->drawmode == NORMAL || t->drawmode == NORMAL_DEBUG)
130 n = &normal[i*size+j];
131 glNormal3f(n->x, n->y, n->z);
134 glVertex3f(i, z, j);
136 z = height[(i+1)*size+j];
137 zcol = (z - t->min_height)*scale;
139 if (t->drawmode == FLAT)
140 glColor3f(0.0, zcol, 1.0 - zcol);
142 if (t->drawmode == NORMAL || t->drawmode == NORMAL_DEBUG)
144 n = &normal[(i+1)*size+j];
145 glNormal3f(n->x, n->y, n->z);
148 glVertex3f(i+1, z, j);
150 glEnd();
153 if (t->drawmode == NORMAL_DEBUG)
155 glDisable(GL_LIGHTING);
156 glColor3f(1.0, 0.0, 0.0);
157 glBegin(GL_LINES);
158 for (i=0; i<size; i++)
160 for (j=0; j<size; j++)
162 struct point p = {i, height[i*size+j], j, 0.0};
163 glVertex3f(p.x, p.y, p.z);
164 point_add(&p, &normal[i*size+j]);
165 glVertex3f(p.x, p.y, p.z);
168 glEnd();
169 glEnable(GL_LIGHTING);
172 glEndList();
175 void terrain_draw(struct terrain *t)
177 int size = t->size;
179 glPushMatrix();
180 glTranslatef(-0.5*size, 0.0, -0.5*size);
182 if (t->drawmode == FLAT)
183 glDisable(GL_LIGHTING);
185 if (t->dirty)
187 build_execute(t);
188 t->dirty = 0;
190 else
192 glCallList(t->drawlist);
195 glEnable(GL_LIGHTING);
197 glPopMatrix();
200 void terrain_smooth(struct terrain *t, float k)
202 int size = t->size;
203 float *height = t->height;
205 t->dirty = 1;
207 int i, j, idx;
208 // left to right
209 for (i=1; i<size; i++)
211 for (j=0; j<size; j++)
213 idx = i*size+j;
214 height[idx] = height[(i-1)*size+j] * (1.0-k) + height[idx] * k;
217 // right to left
218 for (i=size-2; i>-1; i--)
220 for (j=0; j<size; j++)
222 idx = i*size+j;
223 height[idx] = height[(i+1)*size+j] * (1.0-k) + height[idx] * k;
226 // bottom to top
227 for (i=0; i<size; i++)
229 for (j=1; j<size; j++)
231 idx = i*size+j;
232 height[idx] = height[i*size+j-1] * (1.0-k) + height[idx] * k;
235 // top to bottom
236 for (i=0; i<size; i++)
238 for (j=size-2; j>-1; j--)
240 idx = i*size+j;
241 height[idx] = height[i*size+j+1] * (1.0-k) + height[idx] * k;
246 void terrain_clear(struct terrain *t)
248 t->max_height = 1.0;
249 t->min_height = 0.0;
250 memset(t->height, 0, sizeof(float)*t->size*t->size);