Add missing credit for Esperanto translation
[neverball.git] / share / mtrl.c
blob4032350eda7afb7d8f5727ffd98cb2a6ab3efa9e
1 /*
2 * Copyright (C) 2014 Neverball authors
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
15 #include <string.h>
16 #include <stdlib.h>
18 #include "mtrl.h"
19 #include "array.h"
20 #include "common.h"
21 #include "image.h"
22 #include "lang.h"
25 * Material cache.
27 * These routines load materials from SOL files into a common cache
28 * and create mappings from internal SOL indices to this cache. They
29 * can also reload materials from material specification files.
31 * Some unresolved stuff:
33 * Duplicates are ignored. SOLs define materials internally, so
34 * conflicts can arise between different SOLs. Right now materials
35 * start out with the values from the first cached SOL. If the values
36 * are bad, every subsequent SOL will use them. On the upside,
37 * duplicates are uncommon.
39 * Reloading does not reschedule meshes. Mesh counts for each geometry
40 * pass are tested every frame, but cached at load time. Reloading
41 * does not update those counts, which results in weird behaviors,
42 * e.g., opaque materials that are reloaded as transparent becoming
43 * invisible because they are unaccounted for.
45 * Obviously, features that require geometry recomputation, such as
46 * "angle" normal smoothing feature, are not handled by the reloader.
49 static Array mtrls;
51 static struct b_mtrl default_base_mtrl =
53 { 0.8f, 0.8f, 0.8f, 1.0f },
54 { 0.2f, 0.2f, 0.2f, 1.0f },
55 { 0.0f, 0.0f, 0.0f, 1.0f },
56 { 0.0f, 0.0f, 0.0f, 1.0f },
57 { 0.0f }, 0.0f, 0, ""
60 int default_mtrl;
62 /*---------------------------------------------------------------------------*/
65 * Obtain a mtrl ref by name.
67 static int find_mtrl(const char *name)
69 int i, c = array_len(mtrls);
71 for (i = 0; i < c; i++)
73 struct mtrl *mp = array_get(mtrls, i);
75 if (mp->refc > 0 && strcmp(name, mp->base.f) == 0)
76 return i;
78 return -1;
82 * Load a material texture.
84 static GLuint find_texture(const char *name)
86 char path[MAXSTR];
87 GLuint o;
88 int i;
90 for (i = 0; i < ARRAYSIZE(tex_paths); i++)
92 CONCAT_PATH(path, &tex_paths[i], name);
94 if ((o = make_image_from_file(path, IF_MIPMAP)))
95 return o;
97 return 0;
101 * Load GL resources of an initialized material.
103 static void load_mtrl_objects(struct mtrl *mp)
105 /* Make sure not to leak an already loaded object. */
107 if (mp->o)
108 return;
110 /* Load the texture. */
112 if ((mp->o = find_texture(_(mp->base.f))))
114 /* Set the texture to clamp or repeat based on material type. */
116 if (mp->base.fl & M_CLAMP_S)
117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
118 else
119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
121 if (mp->base.fl & M_CLAMP_T)
122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
123 else
124 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
129 * Free GL resources of a material.
131 static void free_mtrl_objects(struct mtrl *mp)
133 if (mp->o)
135 glDeleteTextures(1, &mp->o);
137 mp->o = 0;
142 * Load a material from a base material.
144 static void load_mtrl(struct mtrl *mp, const struct b_mtrl *base)
146 /* Copy the base material. */
148 memcpy(&mp->base, base, sizeof (struct b_mtrl));
150 /* Cache the 32-bit material values for quick comparison. */
152 mp->d = touint(base->d);
153 mp->a = touint(base->a);
154 mp->s = touint(base->s);
155 mp->e = touint(base->e);
156 mp->h = tobyte(base->h[0]);
158 /* Load GL resources. */
160 load_mtrl_objects(mp);
164 * Free a material.
166 static void free_mtrl(struct mtrl *mp)
168 free_mtrl_objects(mp);
172 * Cache a single material.
174 int mtrl_cache(const struct b_mtrl *base)
176 struct mtrl *mp;
178 int mi = find_mtrl(base->f);
180 if (mi < 0)
182 int i, c = array_len(mtrls);
184 /* Find an empty slot. */
186 for (i = 0; i < c; i++)
188 mp = array_get(mtrls, i);
190 if (mp->refc == 0)
192 load_mtrl(mp, base);
193 mp->refc++;
194 return i;
198 /* Allocate a new slot. */
200 if ((mp = array_add(mtrls)))
202 memset(mp, 0, sizeof (*mp));
203 load_mtrl(mp, base);
204 mp->refc++;
205 return array_len(mtrls) - 1;
208 else
210 mp = array_get(mtrls, mi);
211 mp->refc++;
214 return mi;
218 * Free a cached material.
220 void mtrl_free(int mi)
222 if (mtrls)
224 struct mtrl *mp = array_get(mtrls, mi);
226 if (mp->refc > 0)
228 mp->refc--;
230 if (mp->refc == 0)
231 free_mtrl(mp);
237 * Obtain a material pointer.
239 struct mtrl *mtrl_get(int mi)
241 return mtrls ? array_get(mtrls, mi) : NULL;
245 * Cache SOL materials.
247 void mtrl_cache_sol(struct s_base *fp)
249 if (fp->mtrls)
251 free(fp->mtrls);
252 fp->mtrls = NULL;
255 if ((fp->mtrls = calloc(fp->mc, sizeof (*fp->mtrls))))
257 int mi;
259 for (mi = 0; mi < fp->mc; mi++)
260 fp->mtrls[mi] = mtrl_cache(&fp->mv[mi]);
265 * Free cached materials.
267 void mtrl_free_sol(struct s_base *fp)
269 if (fp)
270 if (fp->mtrls)
272 int mi;
274 for (mi = 0; mi < fp->mc; mi++)
275 mtrl_free(fp->mtrls[mi]);
277 free(fp->mtrls);
278 fp->mtrls = NULL;
283 * Reload materials from material specifications.
285 void mtrl_reload(void)
287 if (mtrls)
289 struct b_mtrl base;
291 int i, c = array_len(mtrls);
293 for (i = 0; i < c; i++)
295 struct mtrl *mp = array_get(mtrls, i);
297 /* Read the material specification. */
299 if (mp->refc > 0 && mtrl_read(&base, mp->base.f))
301 free_mtrl(mp);
302 load_mtrl(mp, &base);
309 * Load GL resources of all materials.
311 void mtrl_load_objects(void)
313 int i, c = array_len(mtrls);
315 for (i = 0; i < c; i++)
317 struct mtrl *mp = array_get(mtrls, i);
319 if (mp->refc > 0)
320 load_mtrl_objects(mp);
325 * Delete GL resources of all materials.
327 void mtrl_free_objects(void)
329 int i, c = array_len(mtrls);
331 for (i = 0; i < c; i++)
333 struct mtrl *mp = array_get(mtrls, i);
335 if (mp->refc > 0)
336 free_mtrl_objects(mp);
341 * Initialize material cache.
343 void mtrl_init(void)
345 mtrl_quit();
347 if ((mtrls = array_new(sizeof (struct mtrl))))
349 /* Cache the default material at index 0. */
351 default_mtrl = mtrl_cache(&default_base_mtrl);
356 * Destroy material cache.
358 void mtrl_quit(void)
360 if (mtrls)
362 int i, c = array_len(mtrls);
364 for (i = 0; i < c; i++)
365 free_mtrl(array_get(mtrls, i));
367 array_free(mtrls);
368 mtrls = NULL;
371 /*---------------------------------------------------------------------------*/
374 * This has to match up with mtrl_func_names in solid_base.c.
376 static GLenum mtrl_func_syms[8] = {
377 GL_ALWAYS,
378 GL_EQUAL,
379 GL_GEQUAL,
380 GL_GREATER,
381 GL_LEQUAL,
382 GL_LESS,
383 GL_NEVER,
384 GL_NOTEQUAL
388 * Convert function index to a GL symbol.
390 GLenum mtrl_func(int i)
392 if (i >= 0 && i < ARRAYSIZE(mtrl_func_syms))
393 return mtrl_func_syms[i];
394 else
395 return GL_ALWAYS;
398 /*---------------------------------------------------------------------------*/