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.
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.
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
},
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)
82 * Load a material texture.
84 static GLuint
find_texture(const char *name
)
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
)))
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. */
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
);
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
);
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
)
135 glDeleteTextures(1, &mp
->o
);
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
);
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
)
178 int mi
= find_mtrl(base
->f
);
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
);
198 /* Allocate a new slot. */
200 if ((mp
= array_add(mtrls
)))
202 memset(mp
, 0, sizeof (*mp
));
205 return array_len(mtrls
) - 1;
210 mp
= array_get(mtrls
, mi
);
218 * Free a cached material.
220 void mtrl_free(int mi
)
224 struct mtrl
*mp
= array_get(mtrls
, mi
);
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
)
255 if ((fp
->mtrls
= calloc(fp
->mc
, sizeof (*fp
->mtrls
))))
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
)
274 for (mi
= 0; mi
< fp
->mc
; mi
++)
275 mtrl_free(fp
->mtrls
[mi
]);
283 * Reload materials from material specifications.
285 void mtrl_reload(void)
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
))
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
);
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
);
336 free_mtrl_objects(mp
);
341 * Initialize material cache.
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.
362 int i
, c
= array_len(mtrls
);
364 for (i
= 0; i
< c
; i
++)
365 free_mtrl(array_get(mtrls
, i
));
371 /*---------------------------------------------------------------------------*/
374 * This has to match up with mtrl_func_names in solid_base.c.
376 static GLenum mtrl_func_syms
[8] = {
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
];
398 /*---------------------------------------------------------------------------*/