1 /************************************************************************
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
43 static int render_map_sort(void *e1
, void *e2
)
63 d1
= math_distance(&cp
,&ep
);
67 /* return -1 if this object is out of visual range */
68 if (d1
> wm_data
.distance
)
72 o1->lod = ((d1+8)/16);
77 }else if (o1->lod < 0) {
86 d2
= math_distance(&cp
,&ep
);
90 /* return 1 if e1 is closer to the camera than e2 */
96 static void render_map_genvao(mesh_t
*m
)
99 if (!m
->v
->length
|| !m
->i
->length
)
102 glGenVertexArrays(1,&m
->vao
.list
);
103 glBindVertexArray(m
->vao
.list
);
105 glGenBuffers(1, &m
->vao
.indices
);
106 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, m
->vao
.indices
);
107 glBufferData(GL_ELEMENT_ARRAY_BUFFER
, m
->i
->length
*4, m
->i
->data
, GL_STATIC_DRAW
);
109 glGenBuffers(1, &m
->vao
.vertices
);
110 glBindBuffer(GL_ARRAY_BUFFER
, m
->vao
.vertices
);
111 glBufferData(GL_ARRAY_BUFFER
, m
->v
->length
*4, m
->v
->data
, GL_STATIC_DRAW
);
112 glEnableVertexAttribArray(0);
113 glVertexAttribPointer(0,3,GL_FLOAT
,GL_FALSE
,0,0);
115 glGenBuffers(1, &m
->vao
.normals
);
116 glBindBuffer(GL_ARRAY_BUFFER
, m
->vao
.normals
);
117 glBufferData(GL_ARRAY_BUFFER
, m
->n
->length
*4, m
->n
->data
, GL_STATIC_DRAW
);
118 glEnableVertexAttribArray(1);
119 glVertexAttribPointer(1,3,GL_FLOAT
,GL_FALSE
,0,0);
121 glGenBuffers(1, &m
->vao
.texcoords
);
122 glBindBuffer(GL_ARRAY_BUFFER
, m
->vao
.texcoords
);
123 glBufferData(GL_ARRAY_BUFFER
, m
->t
->length
*4, m
->t
->data
, GL_STATIC_DRAW
);
124 glEnableVertexAttribArray(2);
125 glVertexAttribPointer(2,2,GL_FLOAT
,GL_FALSE
,0,0);
130 static void render_map_calc_frustum(matrix_t
*projection
)
136 matrix_multiply(&mat
,&render_map_data
.view
);
138 /* Extract the numbers for the RIGHT plane */
139 render_map_data
.frustum
[0][0] = mat
.data
[ 3] - mat
.data
[ 0];
140 render_map_data
.frustum
[0][1] = mat
.data
[ 7] - mat
.data
[ 4];
141 render_map_data
.frustum
[0][2] = mat
.data
[11] - mat
.data
[ 8];
142 render_map_data
.frustum
[0][3] = mat
.data
[15] - mat
.data
[12];
144 /* Normalize the result */
145 t
= sqrt( render_map_data
.frustum
[0][0] * render_map_data
.frustum
[0][0] + render_map_data
.frustum
[0][1] * render_map_data
.frustum
[0][1] + render_map_data
.frustum
[0][2] * render_map_data
.frustum
[0][2] );
146 render_map_data
.frustum
[0][0] /= t
;
147 render_map_data
.frustum
[0][1] /= t
;
148 render_map_data
.frustum
[0][2] /= t
;
149 render_map_data
.frustum
[0][3] /= t
;
151 /* Extract the numbers for the LEFT plane */
152 render_map_data
.frustum
[1][0] = mat
.data
[ 3] + mat
.data
[ 0];
153 render_map_data
.frustum
[1][1] = mat
.data
[ 7] + mat
.data
[ 4];
154 render_map_data
.frustum
[1][2] = mat
.data
[11] + mat
.data
[ 8];
155 render_map_data
.frustum
[1][3] = mat
.data
[15] + mat
.data
[12];
157 /* Normalize the result */
158 t
= sqrt( render_map_data
.frustum
[1][0] * render_map_data
.frustum
[1][0] + render_map_data
.frustum
[1][1] * render_map_data
.frustum
[1][1] + render_map_data
.frustum
[1][2] * render_map_data
.frustum
[1][2] );
159 render_map_data
.frustum
[1][0] /= t
;
160 render_map_data
.frustum
[1][1] /= t
;
161 render_map_data
.frustum
[1][2] /= t
;
162 render_map_data
.frustum
[1][3] /= t
;
164 /* Extract the BOTTOM plane */
165 render_map_data
.frustum
[2][0] = mat
.data
[ 3] + mat
.data
[ 1];
166 render_map_data
.frustum
[2][1] = mat
.data
[ 7] + mat
.data
[ 5];
167 render_map_data
.frustum
[2][2] = mat
.data
[11] + mat
.data
[ 9];
168 render_map_data
.frustum
[2][3] = mat
.data
[15] + mat
.data
[13];
170 /* Normalize the result */
171 t
= sqrt( render_map_data
.frustum
[2][0] * render_map_data
.frustum
[2][0] + render_map_data
.frustum
[2][1] * render_map_data
.frustum
[2][1] + render_map_data
.frustum
[2][2] * render_map_data
.frustum
[2][2] );
172 render_map_data
.frustum
[2][0] /= t
;
173 render_map_data
.frustum
[2][1] /= t
;
174 render_map_data
.frustum
[2][2] /= t
;
175 render_map_data
.frustum
[2][3] /= t
;
177 /* Extract the TOP plane */
178 render_map_data
.frustum
[3][0] = mat
.data
[ 3] - mat
.data
[ 1];
179 render_map_data
.frustum
[3][1] = mat
.data
[ 7] - mat
.data
[ 5];
180 render_map_data
.frustum
[3][2] = mat
.data
[11] - mat
.data
[ 9];
181 render_map_data
.frustum
[3][3] = mat
.data
[15] - mat
.data
[13];
183 /* Normalize the result */
184 t
= sqrt( render_map_data
.frustum
[3][0] * render_map_data
.frustum
[3][0] + render_map_data
.frustum
[3][1] * render_map_data
.frustum
[3][1] + render_map_data
.frustum
[3][2] * render_map_data
.frustum
[3][2] );
185 render_map_data
.frustum
[3][0] /= t
;
186 render_map_data
.frustum
[3][1] /= t
;
187 render_map_data
.frustum
[3][2] /= t
;
188 render_map_data
.frustum
[3][3] /= t
;
190 /* Extract the FAR plane */
191 render_map_data
.frustum
[4][0] = mat
.data
[ 3] - mat
.data
[ 2];
192 render_map_data
.frustum
[4][1] = mat
.data
[ 7] - mat
.data
[ 6];
193 render_map_data
.frustum
[4][2] = mat
.data
[11] - mat
.data
[10];
194 render_map_data
.frustum
[4][3] = mat
.data
[15] - mat
.data
[14];
196 /* Normalize the result */
197 t
= sqrt( render_map_data
.frustum
[4][0] * render_map_data
.frustum
[4][0] + render_map_data
.frustum
[4][1] * render_map_data
.frustum
[4][1] + render_map_data
.frustum
[4][2] * render_map_data
.frustum
[4][2] );
198 render_map_data
.frustum
[4][0] /= t
;
199 render_map_data
.frustum
[4][1] /= t
;
200 render_map_data
.frustum
[4][2] /= t
;
201 render_map_data
.frustum
[4][3] /= t
;
203 /* Extract the NEAR plane */
204 render_map_data
.frustum
[5][0] = mat
.data
[ 3] + mat
.data
[ 2];
205 render_map_data
.frustum
[5][1] = mat
.data
[ 7] + mat
.data
[ 6];
206 render_map_data
.frustum
[5][2] = mat
.data
[11] + mat
.data
[10];
207 render_map_data
.frustum
[5][3] = mat
.data
[15] + mat
.data
[14];
209 /* Normalize the result */
210 t
= sqrt( render_map_data
.frustum
[5][0] * render_map_data
.frustum
[5][0] + render_map_data
.frustum
[5][1] * render_map_data
.frustum
[5][1] + render_map_data
.frustum
[5][2] * render_map_data
.frustum
[5][2] );
211 render_map_data
.frustum
[5][0] /= t
;
212 render_map_data
.frustum
[5][1] /= t
;
213 render_map_data
.frustum
[5][2] /= t
;
214 render_map_data
.frustum
[5][3] /= t
;
217 int render_map_point_in_frustum(v3_t
*p
)
220 for (i
=0; i
<6; i
++) {
221 if (((render_map_data
.frustum
[i
][0]*p
->x
)+(render_map_data
.frustum
[i
][1]*p
->y
)+(render_map_data
.frustum
[i
][2]*p
->z
)+render_map_data
.frustum
[i
][3]) <= 0)
227 int render_map_bounds_in_frustum(v3_t
*p
, aabox_t
*b
)
233 if (render_map_point_in_frustum(p
))
268 for (i
=0; i
<6; i
++) {
269 for (k
=0; k
<8; k
++) {
271 render_map_data
.frustum
[i
][0]*v
[k
].x
)
272 +(render_map_data
.frustum
[i
][1]*v
[k
].y
)
273 +(render_map_data
.frustum
[i
][2]*v
[k
].z
)
274 +render_map_data
.frustum
[i
][3]) > 0
286 mapobj_t
*render_map_chunk(mapobj_t
*o
)
288 if (!render_map_data
.objects
) {
289 render_map_data
.mutex
= mutex_create();
290 render_map_data
.objects
= array_create(ARRAY_TYPE_PTR
);
293 mutex_lock(render_map_data
.mutex
);
294 array_push_ptr(render_map_data
.objects
,o
);
295 mutex_unlock(render_map_data
.mutex
);
300 /* render 3d graphics to the frame */
301 void render_map(camera_t
*cam
, v4_t
*plane
)
303 static v4_t p
= {1000000.0,0.0,-1.0,0.0};
309 matrix_t
*projection
;
310 if (!render_map_data
.objects
|| !render_map_data
.objects
->length
)
313 if (!render_map_data
.shader
) {
314 render_map_data
.shader
= shader_create("map");
315 shader_attribute(render_map_data
.shader
,0,"position");
316 shader_attribute(render_map_data
.shader
,1,"normals");
317 shader_attribute(render_map_data
.shader
,2,"texcoords");
318 /* possibly a colours attribute as well */
321 shader_enable(render_map_data
.shader
);
323 camera_view_matrix(&render_map_data
.view
,cam
);
325 projection
= render_get_projection_matrix();
327 shader_uniform_matrix(render_map_data
.shader
,"projectionMatrix",projection
);
328 shader_uniform_matrix(render_map_data
.shader
,"viewMatrix",&render_map_data
.view
);
330 /* calculate the frustum */
331 render_map_calc_frustum(projection
);
333 render_map_data
.sorted
= NULL
;
335 mutex_lock(render_map_data
.mutex
);
336 for (i
=0; i
<render_map_data
.objects
->length
; i
++) {
337 o
= ((mapobj_t
**)(render_map_data
.objects
->data
))[i
];
338 /* check if we're meant to touch it */
339 if (!o
|| !o
->objs
[0].meshes
)
341 /*if (!render_map_bounds_in_frustum(&o->pos,&o->bounds))
343 /* sort objects by distance, ignoring anything that can't be seen */
344 render_map_data
.sorted
= list_insert_cmp(&render_map_data
.sorted
,o
,render_map_sort
);
346 mutex_unlock(render_map_data
.mutex
);
348 o
= render_map_data
.sorted
;
350 /* now render chunks, furthest first */
353 matrix_translate_v(&mat
,&o
->pos
);
354 shader_uniform_matrix(render_map_data
.shader
,"transformationMatrix",&mat
);
356 light_bind_near(render_map_data.shader,&o->pos);
359 lo
= &o
->objs
[o
->lod
];
361 if (lo
&& lo
->meshes
) {
362 for (i
=0; i
<lo
->meshes
->length
; i
++) {
363 m
= ((mesh_t
**)lo
->meshes
->data
)[i
];
364 /* create buffers if necessary and fill with data */
366 render_map_genvao(m
);
371 glBindVertexArray(m
->vao
.list
);
372 glEnableVertexAttribArray(0);
374 mat_use(m
->mat
,render_map_data
.shader
);
376 glEnableVertexAttribArray(1);
377 glEnableVertexAttribArray(2);
378 glDrawElements(m
->mode
,m
->i
->length
,GL_UNSIGNED_INT
,NULL
);
383 /* TODO: render block objects */
389 glDisableVertexAttribArray(0);
390 glDisableVertexAttribArray(1);
391 glDisableVertexAttribArray(2);
392 glBindVertexArray(0);
394 shader_disable(render_map_data
.shader
);