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 ************************************************************************/
39 static int render3d_sort(void *e1
, void *e2
)
51 ep
.x
= ((object_t
*)e1
)->pos
.x
;
52 ep
.y
= ((object_t
*)e1
)->pos
.y
;
53 ep
.z
= ((object_t
*)e1
)->pos
.z
;
54 d1
= math_distance(&cp
,&ep
);
58 /* return -1 if this object is out of visual range */
59 if (d1
> wm_data
.distance
)
62 /* TODO: return -1 if this object is completely behind the camera */
64 ep
.x
= ((object_t
*)e2
)->pos
.x
;
65 ep
.y
= ((object_t
*)e2
)->pos
.y
;
66 ep
.z
= ((object_t
*)e2
)->pos
.z
;
67 d2
= math_distance(&cp
,&ep
);
71 /* return 1 if e1 is closer to the camera than e2 */
77 static void render3d_step(object_t
*o
)
83 for (i=0; i<o->meshes->length; i++) {
84 m = ((mesh_t**)o->meshes->data)[i];
85 if (m->vbo.state == 1)
92 static void render3d_genvao(mesh_t
*m
)
94 if (!m
->v
->length
|| !m
->i
->length
)
97 glGenVertexArrays(1,&m
->vao
.list
);
98 glBindVertexArray(m
->vao
.list
);
100 glGenBuffers(1, &m
->vao
.indices
);
101 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, m
->vao
.indices
);
102 glBufferData(GL_ELEMENT_ARRAY_BUFFER
, m
->i
->length
*4, m
->i
->data
, GL_STATIC_DRAW
);
104 glGenBuffers(1, &m
->vao
.vertices
);
105 glBindBuffer(GL_ARRAY_BUFFER
, m
->vao
.vertices
);
106 glBufferData(GL_ARRAY_BUFFER
, m
->v
->length
*4, m
->v
->data
, GL_STATIC_DRAW
);
107 glEnableVertexAttribArray(0);
108 glVertexAttribPointer(0,3,GL_FLOAT
,GL_FALSE
,0,0);
110 if (m
->n
&& m
->n
->length
) {
111 glGenBuffers(1, &m
->vao
.normals
);
112 glBindBuffer(GL_ARRAY_BUFFER
, m
->vao
.normals
);
113 glBufferData(GL_ARRAY_BUFFER
, m
->n
->length
*4, m
->n
->data
, GL_STATIC_DRAW
);
114 glEnableVertexAttribArray(1);
115 glVertexAttribPointer(1,3,GL_FLOAT
,GL_FALSE
,0,0);
118 if (m
->t
&& m
->t
->length
) {
119 glGenBuffers(1, &m
->vao
.texcoords
);
120 glBindBuffer(GL_ARRAY_BUFFER
, m
->vao
.texcoords
);
121 glBufferData(GL_ARRAY_BUFFER
, m
->t
->length
*4, m
->t
->data
, GL_STATIC_DRAW
);
122 glEnableVertexAttribArray(2);
123 glVertexAttribPointer(2,2,GL_FLOAT
,GL_FALSE
,0,0);
129 static void render3d_regenvao(mesh_t
*m
)
133 /* find a 3d object */
134 object_t
*render3d_object_find(int id
)
136 if (render3d_data
.objects
) {
138 object_t
**o
= render3d_data
.objects
->data
;
139 for (i
=0; i
<render3d_data
.objects
->length
; i
++) {
140 if (o
[i
] && o
[i
]->id
== id
)
148 /* destroy a 3d object */
149 void render3d_object_free(object_t
*o
)
152 int i
= array_find_ptr(render3d_data
.objects
,o
);
158 while (o
->ignore
!= 3) {
162 ((unsigned char**)(render3d_data
.objects
->data
))[i
] = NULL
;
164 while ((m
= array_pop_ptr(o
->meshes
))) {
167 array_free(o
->meshes
,1);
171 /* create a new 3d object */
172 object_t
*render3d_object_create()
174 static int object_ids
= 1;
175 object_t
*o
= malloc(sizeof(object_t
));
177 o
->meshes
= array_create(ARRAY_TYPE_PTR
);
178 o
->id
= object_ids
++;
192 if (!render3d_data
.objects
)
193 render3d_data
.objects
= array_create(ARRAY_TYPE_PTR
);
195 array_push_ptr(render3d_data
.objects
,o
);
201 object_t
*render3d_model(model_t
*mod
, v3_t
*pos
)
205 object_t
*o
= render3d_object_create();
212 for (i
=0; i
<mod
->meshes
->length
; i
++) {
213 m
= ((mesh_t
**)(mod
->meshes
->data
))[i
];
215 array_push_ptr(o
->meshes
,m
);
224 object_t
*render3d_mesh(mesh_t
*m
, v3_t
*pos
)
226 object_t
*o
= render3d_object_create();
233 array_push_ptr(o
->meshes
,m
);
238 object_t
*render3d_cube(float scale
, v3_t
*pos
, material_t
*mat
)
313 object_t
*o
= render3d_object_create();
318 m
= mesh_create_material(mat
);
320 for (i
=0; i
<24; i
++) {
321 array_push_v2t(m
->t
,&t
[i
]);
325 array_push_v3t(m
->v
,&v
[i
]);
327 for (i
=0; i
<36; i
++) {
328 array_push_int(m
->i
,indices
[i
]);
331 array_push_ptr(o
->meshes
,m
);
333 object_calc_normals(o
);
340 void render3d_set_projection_matrix()
354 fov
= math_degrees_to_radians(fov
/2.0);
356 ratio
= (float)wm_data
.size
.width
/(float)wm_data
.size
.height
;
357 y
= (1.0/tan(fov
))*ratio
;
359 z
= far_plane
-near_plane
;
361 matrix_init(&render3d_data
.projection
);
363 render3d_data
.projection
.data
[0] = x
;
364 render3d_data
.projection
.data
[5] = y
;
365 render3d_data
.projection
.data
[10] = -((far_plane
+near_plane
)/z
);
366 render3d_data
.projection
.data
[11] = -1;
367 render3d_data
.projection
.data
[14] = -((2.0*near_plane
*far_plane
)/z
);
368 render3d_data
.projection
.data
[15] = 0;
371 /* render 3d graphics to the frame */
378 shader_t
*active_shader
;
379 if (!render3d_data
.objects
|| !render3d_data
.objects
->length
)
382 glEnable(GL_DEPTH_TEST
);
383 if (!render3d_data
.shader
) {
384 render3d_data
.shader
= shader_create("model");
385 shader_attribute(render3d_data
.shader
,0,"position");
386 shader_attribute(render3d_data
.shader
,1,"normals");
387 shader_attribute(render3d_data
.shader
,2,"texcoords");
388 /* possibly a colours attribute as well */
391 shader_enable(render3d_data
.shader
);
392 active_shader
= render3d_data
.shader
;
394 camera_view_matrix(&render3d_data
.view
);
396 shader_uniform_matrix(active_shader
,"projectionMatrix",&render3d_data
.projection
);
397 shader_uniform_matrix(active_shader
,"viewMatrix",&render3d_data
.view
);
399 render3d_data
.sorted
= NULL
;
401 for (i
=0; i
<render3d_data
.objects
->length
; i
++) {
402 o
= ((object_t
**)(render3d_data
.objects
->data
))[i
];
403 /* check if we're meant to touch it */
414 /* call step on each object, this may modify the data (such as with animated models) */
415 if (o
->m
&& o
->m
->step
)
417 /* sort objects by distance, ignoring anything that can't be seen */
418 render3d_data
.sorted
= list_insert_cmp(&render3d_data
.sorted
,o
,render3d_sort
);
421 o
= render3d_data
.sorted
;
422 /* now render objects, furthest first */
425 matrix_scale_v(&mat
,&o
->scale
);
426 matrix_rotate_deg_z(&mat
,o
->rot
.z
);
427 matrix_rotate_deg_y(&mat
,o
->rot
.y
);
428 matrix_rotate_deg_x(&mat
,o
->rot
.x
);
429 matrix_translate_v(&mat
,&o
->pos
);
430 shader_uniform_matrix(active_shader
,"transformationMatrix",&mat
);
431 for (i
=0; i
<o
->meshes
->length
; i
++) {
432 m
= ((mesh_t
**)o
->meshes
->data
)[i
];
433 /* create buffers if necessary and fill with data */
436 }else if (m
->vao
.state
== 2) {
437 render3d_regenvao(m
);
443 glBindVertexArray(m
->vao
.list
);
444 glEnableVertexAttribArray(0);
446 mat_use(m
->mat
,active_shader
);
448 /* use vertex, normal, and texcoord or colour arrays */
449 if (m
->vao
.normals
) {
450 glEnableVertexAttribArray(1);
452 glDisableVertexAttribArray(1);
454 if (m
->vao
.texcoords
) {
455 glEnableVertexAttribArray(2);
457 glDisableVertexAttribArray(2);
462 glPointSize(m
->option
);
465 glLineWidth(m
->option
);
469 glDrawElements(m
->mode
,m
->i
->length
,GL_UNSIGNED_INT
,NULL
);
480 glDrawElements(m
->mode
,m
->i
->length
,GL_UNSIGNED_INT
,NULL
);
485 glBindVertexArray(0);
487 shader_disable(active_shader
);