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 ************************************************************************/
28 material_t
*materials
;
30 GLuint current_texture
[8];
43 material_t
*mat_find(char* name
)
45 material_t
*m
= mat_data
.materials
;
48 if (!strcmp(m
->name
,name
))
56 /* create a new blank material */
57 material_t
*mat_create()
59 material_t
*mat
= malloc(sizeof(material_t
));
60 mat
->id
= mat_data
.ids
++;
62 mat
->options
= MATOPT_BFCULL
;
63 array_init(&mat
->textures
,ARRAY_TYPE_PTR
);
66 mat
->reflectivity
= 0.0;
69 mat_data
.materials
= list_push(&mat_data
.materials
,mat
);
75 void mat_free(material_t
*mat
)
81 mat_data
.materials
= list_remove(&mat_data
.materials
,mat
);
83 while ((tex
= array_pop_ptr(&mat
->textures
))) {
87 array_free(&mat
->textures
,0);
92 /* create a material from a texture */
93 material_t
*mat_from_tex(texture_t
*tex
)
95 material_t
*mat
= mat_create();
96 array_push_ptr(&mat
->textures
,tex
);
97 strcpy(mat
->name
,tex
->name
);
102 /* create a material from pixel data */
103 material_t
*mat_from_pixels(image_t
*p
)
106 material_t
*mat
= mat_create();
107 tex
= tex_from_pixels(p
);
108 array_push_ptr(&mat
->textures
,tex
);
109 strcpy(mat
->name
,tex
->name
);
114 /* create a material from an image */
115 material_t
*mat_from_image(char* type
, char* file
)
120 tex
= tex_from_image(type
,file
);
125 array_push_ptr(&mat
->textures
,tex
);
127 strcpy(mat
->name
,tex
->name
);
132 /* combine size images into a texture cube */
133 material_t
*mat_from_box(char* front
, char* back
, char* left
, char* right
, char* top
, char* bottom
)
138 tex
= tex_from_box(front
,back
,left
,right
,top
,bottom
);
143 array_push_ptr(&mat
->textures
,tex
);
145 strcpy(mat
->name
,tex
->name
);
150 /* create a material from a colour */
151 material_t
*mat_from_colour(colour_t
*c
)
156 snprintf(buff
,256,"rgba-%d-%d-%d-%d",c
->r
,c
->g
,c
->b
,c
->a
);
158 tex
= tex_from_rgba(1,1,c
->r
,c
->g
,c
->b
,c
->a
);
163 array_push_ptr(&mat
->textures
,tex
);
165 strcpy(mat
->name
,buff
);
170 /* add a second texture to a material from an image */
171 int mat_add_image(material_t
*mat
, char* type
, char* file
)
174 tex
= tex_from_image(type
,file
);
178 array_push_ptr(&mat
->textures
,tex
);
183 /* add a new texture to a material */
184 int mat_add_tex(material_t
*mat
, texture_t
*tex
)
189 array_push_ptr(&mat
->textures
,tex
);
194 /* add a new texture from a colour to a material */
195 int mat_add_colour(material_t
*mat
, colour_t
*c
)
201 tex
= tex_from_rgba(1,1,c
->r
,c
->g
,c
->b
,c
->a
);
205 array_push_ptr(&mat
->textures
,tex
);
210 static void mat_apply_opts(uint32_t options
)
212 /* back face culling */
213 if ((options
&MATOPT_BFCULL
) == MATOPT_BFCULL
) {
214 if (!mat_data
.culling
) {
215 glEnable(GL_CULL_FACE
);
217 mat_data
.culling
= 1;
219 }else if (mat_data
.culling
) {
220 glDisable(GL_CULL_FACE
);
221 mat_data
.culling
= 0;
225 if ((options
&MATOPT_ADDITIVE_BLEND
) == MATOPT_ADDITIVE_BLEND
) {
226 if (!mat_data
.blended
) {
228 glEnable(GL_LINE_SMOOTH
);
229 mat_data
.blended
= 1;
231 if (mat_data
.blend_mode
!= GL_ONE
) {
232 glBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
233 mat_data
.blend_mode
= GL_ONE
;
235 }else if ((options
&MATOPT_ALPHA_BLEND
) == MATOPT_ALPHA_BLEND
) {
236 if (!mat_data
.blended
) {
238 glEnable(GL_LINE_SMOOTH
);
239 mat_data
.blended
= 1;
241 if (mat_data
.blend_mode
!= GL_ONE_MINUS_SRC_ALPHA
) {
242 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
243 mat_data
.blend_mode
= GL_ONE_MINUS_SRC_ALPHA
;
245 }else if (mat_data
.blended
) {
247 mat_data
.blended
= 0;
248 mat_data
.blend_mode
= GL_ZERO
;
251 if ((options
&MATOPT_SDF_ALPHA
) == MATOPT_SDF_ALPHA
) {
252 if (opengl_has_psdf()) {
253 shader_uniform_float(NULL
,"alphafunc",2.0);
255 shader_uniform_float(NULL
,"alphafunc",1.0);
257 }else if ((options
&MATOPT_ALPHA_TEST
) == MATOPT_ALPHA_TEST
) {
258 shader_uniform_float(NULL
,"alphafunc",1.0);
260 shader_uniform_float(NULL
,"alphafunc",0.0);
264 static void mat_bind(GLuint tex
, GLenum type
, uint8_t slot
)
267 if (slot
< 0 || slot
> 7)
270 if (mat_data
.current_texture
[slot
] == tex
)
275 glActiveTexture(GL_TEXTURE0
);
278 glActiveTexture(GL_TEXTURE1
);
281 glActiveTexture(GL_TEXTURE2
);
284 glActiveTexture(GL_TEXTURE3
);
287 glActiveTexture(GL_TEXTURE4
);
290 glActiveTexture(GL_TEXTURE5
);
293 glActiveTexture(GL_TEXTURE6
);
296 glActiveTexture(GL_TEXTURE7
);
302 snprintf(buff
,32,"texture%u",slot
);
304 glBindTexture(type
,tex
);
306 mat_data
.current_texture
[slot
] = tex
;
308 shader_uniform_int(NULL
,buff
,slot
);
311 /* bind a texture and apply options */
312 int mat_bind_with_opts(GLuint tex
, uint32_t options
)
315 mat_bind(tex
,GL_TEXTURE_2D
,0);
316 mat_apply_opts(options
);
318 for (i
=1; i
<8; i
++) {
319 mat_bind(0,GL_TEXTURE_2D
,i
);
327 void mat_use(material_t
*mat
, shader_t
*shader
)
329 if (mat
->textures
.length
) {
332 for (i
=0; i
<8; i
++) {
333 tex
= array_get_ptr(&mat
->textures
,i
);
337 mat_bind(tex
->glid
,tex
->type
,i
);
338 }else if (mat_data
.current_texture
[i
]) {
339 mat_bind(0,GL_TEXTURE_2D
,i
);
342 mat_apply_opts(mat
->options
);
344 mat_bind_with_opts(0,mat
->options
);
347 /* specular values */
348 shader_uniform_float(shader
,"shininess",mat
->shininess
);
349 shader_uniform_float(shader
,"reflectivity",mat
->reflectivity
);
350 shader_uniform_float(shader
,"bumpiness",mat
->bumpiness
);
353 /* set the shininess and reflectivity of a material */
354 void mat_shininess(material_t
*mat
, float shininess
, float reflectivity
)
356 mat
->shininess
= shininess
;
357 mat
->reflectivity
= reflectivity
;
360 /* set the bumpiness (for bump mapping) of a material */
361 void mat_bumpiness(material_t
*mat
, float bumpiness
)
363 mat
->bumpiness
= bumpiness
;
366 /* set the name of a material */
367 void mat_name(material_t
*mat
, char* name
)
369 strncpy(mat
->name
,name
,256);
372 /* set the options for a material, return the previous options */
373 uint32_t mat_options(material_t
*mat
, uint32_t opt
)
375 uint32_t o
= mat
->options
;
376 if (opt
!= MATOPT_GET
)