some meshgen and map rendering updates
[voxelands-alt.git] / src / graphics / texture.c
blobdb4b491907da00633e27b154aeb71a7023130ed5
1 /************************************************************************
2 * texture.c
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 ************************************************************************/
20 #include "common.h"
21 #include "graphics.h"
22 #include "list.h"
24 #include <string.h>
26 static struct {
27 texture_t *textures;
28 int ids;
29 } tex_data = {
30 NULL,
34 /* generate the hardware texture */
35 int tex_generate(texture_t *tex)
37 GLenum types[6] = {
38 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
39 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
40 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
41 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
42 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
43 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
45 int i;
46 int c;
47 int b = 0;
48 int t = 0;
49 int m = 0;
50 GLenum type;
51 GLenum e;
53 /* can't generate a texture if there's no data or no OpenGL */
54 if (!tex || !wm_data.isinit)
55 return 1;
57 e = glGetError();
59 /* delete the old texture, if it exists */
60 if (tex->state) {
61 glDeleteTextures(1, &tex->glid);
62 e = glGetError();
63 if (e != GL_NO_ERROR) {
64 char* es = opengl_error_string(e);
65 vlprintf(CN_ERROR, "%d %s",__LINE__,es);
66 return 1;
70 /* create a new texture */
71 glGenTextures(1, &tex->glid);
72 e = glGetError();
73 if (e != GL_NO_ERROR) {
74 char* es = opengl_error_string(e);
75 vlprintf(CN_ERROR, "%d %s",__LINE__,es);
76 return 1;
79 glActiveTexture(GL_TEXTURE0);
80 glBindTexture(tex->type, tex->glid);
81 e = glGetError();
82 if (e != GL_NO_ERROR) {
83 char* es = opengl_error_string(e);
84 vlprintf(CN_ERROR, "%d %s",__LINE__,es);
85 return 1;
88 b = opengl_has_bilinear();
89 t = opengl_has_trilinear();
90 m = opengl_has_mipmap();
92 c = 1;
93 if (tex->type == GL_TEXTURE_CUBE_MAP)
94 c = 6;
95 for (i=0; i<c; i++) {
96 if (tex->type == GL_TEXTURE_CUBE_MAP) {
97 type = types[i];
98 }else{
99 type = GL_TEXTURE_2D;
101 /* draw the pixels to the texture */
102 glTexImage2D(type, 0, GL_RGBA8, tex->px[i].w, tex->px[i].h , 0, GL_RGBA, GL_UNSIGNED_BYTE, tex->px[i].pixels);
103 e = glGetError();
104 if (e != GL_NO_ERROR) {
105 char* es = opengl_error_string(e);
106 vlprintf(CN_ERROR, "%d %s",__LINE__,es);
107 return 1;
111 if (m) {
112 glGenerateMipmap(tex->type);
113 glTexParameteri(tex->type, GL_TEXTURE_WRAP_S, GL_REPEAT);
114 glTexParameteri(tex->type, GL_TEXTURE_WRAP_T, GL_REPEAT);
117 if (t) {
118 glTexParameteri(tex->type,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
119 if (m) {
120 glTexParameteri(tex->type,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
121 }else{
122 glTexParameteri(tex->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
124 }else if (b) {
125 glTexParameteri(tex->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
126 glTexParameteri(tex->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
127 }else{
128 glTexParameteri(tex->type, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
129 glTexParameteri(tex->type, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
132 if (opengl_has_anisotropic()) {
133 float ma = opengl_max_anisotropic();
134 glTexParameterf(tex->type, GL_TEXTURE_MAX_ANISOTROPY_EXT, ma);
137 e = glGetError();
138 if (e != GL_NO_ERROR) {
139 char* es = opengl_error_string(e);
140 vlprintf(CN_ERROR, "%d %s",__LINE__,es);
141 return 1;
144 if (tex->type == GL_TEXTURE_CUBE_MAP) {
145 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
146 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
149 tex->state = 1;
151 return 0;
154 /* add a new image to the cache */
155 texture_t *tex_create()
157 texture_t *tex = malloc(sizeof(texture_t));
158 if (tex == NULL)
159 return NULL;
161 tex->w = 0;
162 tex->h = 0;
163 tex->xf = 0;
164 tex->yf = 0;
165 tex->name[0] = 0;
166 tex->px = NULL;
167 tex->id = tex_data.ids++;
168 tex->glid = 0;
169 tex->type = GL_TEXTURE_2D;
170 tex->state = 0;
172 tex_data.textures = list_push(&tex_data.textures,tex);
174 return tex;
177 /* free a texture */
178 void tex_free(texture_t *tex)
180 if (!tex)
181 return;
182 tex_data.textures = list_remove(&tex_data.textures,tex);
183 if (tex->glid)
184 glDeleteTextures(1, &tex->glid);
185 if (tex->px && tex->type == GL_TEXTURE_CUBE_MAP)
186 free(tex->px);
187 free(tex);
190 /* load an image to a texture */
191 texture_t *tex_from_image(char* type, char* file)
193 texture_t *t;
194 /* get the image */
195 image_t *p;
197 t = tex_data.textures;
198 while (t) {
199 if (!strcmp(t->name,file))
200 return t;
201 t = t->next;
204 p = image_load(type,file);
205 if (!p) {
206 uint8_t r;
207 uint8_t g;
208 uint8_t b;
209 r = math_rand_range(0,255);
210 g = math_rand_range(0,255);
211 b = math_rand_range(0,255);
212 return tex_from_rgba(32,32,r,g,b,255);
215 /* and make a texture out of it */
216 t = tex_from_pixels(p);
217 if (t)
218 strncpy(t->name,file,256);
220 return t;
223 /* create a texture cube */
224 texture_t *tex_from_box(char* front, char* back, char* left, char* right, char* top, char* bottom)
226 int i;
227 texture_t *t;
228 image_t *p[6];
230 p[0] = image_load("texture",front);
231 if (!p[0])
232 return NULL;
233 p[1] = image_load("texture",back);
234 if (!p[1])
235 return NULL;
236 p[2] = image_load("texture",left);
237 if (!p[2])
238 return NULL;
239 p[3] = image_load("texture",right);
240 if (!p[3])
241 return NULL;
242 p[4] = image_load("texture",top);
243 if (!p[4])
244 return NULL;
245 p[5] = image_load("texture",bottom);
246 if (!p[5])
247 return NULL;
249 t = tex_create();
250 if (!t)
251 return NULL;
253 snprintf(t->name,256,"box-%s-%s-%s-%s-%s-%s",front,back,left,right,top,bottom);
255 t->type = GL_TEXTURE_CUBE_MAP;
257 t->px = malloc(sizeof(image_t)*6);
258 if (!t->px) {
259 tex_free(t);
260 return NULL;
263 t->w = p[0]->w;
264 t->h = p[0]->h;
265 t->xf = 1.0/(GLfloat)p[0]->w;
266 t->yf = 1.0/(GLfloat)p[0]->h;
268 for (i=0; i<6; i++) {
269 t->px[i].w = p[i]->w;
270 t->px[i].h = p[i]->h;
271 t->px[i].pixels = p[i]->pixels;
274 return t;
277 /* create a texture from pixel data */
278 texture_t *tex_from_pixels(image_t *px)
280 texture_t *tex;
281 if (!px)
282 return NULL;
284 tex = tex_create();
285 if (tex == NULL)
286 return NULL;
288 tex->w = px->w;
289 tex->h = px->h;
290 tex->px = px;
291 tex->xf = 1.0/(GLfloat)px->w;
292 tex->yf = 1.0/(GLfloat)px->h;
294 if (tex_generate(tex))
295 tex->state = 0;
297 return tex;
300 /* update a texture from pixel data */
301 texture_t *tex_update_pixels(texture_t *tex, image_t *px)
303 if (!tex)
304 return tex_from_pixels(px);
306 tex->w = px->w;
307 tex->h = px->h ;
308 tex->px = px;
309 tex->xf = 1.0/(GLfloat)px->w;
310 tex->yf = 1.0/(GLfloat)px->h;
312 if (tex_generate(tex))
313 tex->state = 0;
315 tex_free(tex);
317 return NULL;
320 /* create a transparent texture */
321 texture_t *tex_from_rgba(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
323 char n[256];
324 texture_t *t;
325 image_t *p;
327 snprintf(n,256,"rgba-%u-%u-%u-%u-%d-%d",r,g,b,a,x,y);
329 t = tex_data.textures;
330 while (t) {
331 if (!strcmp(t->name,n))
332 return t;
333 t = t->next;
336 p = image_rgba(x,y,r,g,b,a);
337 if (!p)
338 return NULL;
340 t = tex_from_pixels(p);
341 strcpy(t->name,n);
343 return t;