29#define NAEV_ORTHO_SCALE 10.
30#define NAEV_ORTHO_DIST 9.*M_SQRT2
32typedef struct Material_ {
34 GLfloat Ka[3], Kd[3], Ks[3], Ke[3];
35 GLfloat Ns, Ni,
d, bm;
36 glTexture *map_Kd, *map_Ks, *map_Ke, *map_Bump;
46typedef struct Object_ {
60static unsigned int emptyTextureRefs= 0;
62static void mesh_create(
Mesh **meshes,
const char* name,
63 Vertex *corners,
int material )
68 ERR(_(
"No name for current part"));
70 ERR(_(
"No material for current part"));
73 mesh->name = strdup(name);
76 mesh->material = material;
80static int readGLfloat( GLfloat *dest,
int how_many,
char **saveptr )
85 while ((token = SDL_strtokr(NULL, DELIM, saveptr)) != NULL) {
87 sscanf(token,
"%lf", &
d);
88 assert(num <= how_many);
92 assert(num == how_many);
96static int readGLmaterial( GLfloat col[3],
char **saveptr )
98 int ret = readGLfloat( col, 3, saveptr );
108static void materials_readFromFile(
const char *filename,
Material **materials )
110 char *filebuf, *filesaveptr, *line;
112 DEBUG(_(
"Loading material from %s"), filename);
116 ERR(_(
"Cannot open object file %s"), filename);
120 line = SDL_strtokr(filebuf,
"\n", &filesaveptr);
121 while (line != NULL) {
123 char *saveptr, *copy_filename, *texture_filename;
124 token = SDL_strtokr(line, DELIM, &saveptr);
128 }
else if (strcmp(token,
"newmtl") == 0) {
129 token = SDL_strtokr(NULL, DELIM, &saveptr);
131 curr->name = strdup(token);
136 curr->map_Kd = curr->map_Ks = curr->map_Ke = curr->map_Bump = NULL;
137 DEBUG(_(
"Reading new material %s"), curr->name);
138 }
else if (strcmp(token,
"Ns") == 0) {
139 readGLfloat(&curr->Ns, 1, &saveptr);
140 }
else if (strcmp(token,
"Ni") == 0) {
141 readGLfloat(&curr->Ni, 1, &saveptr);
142 }
else if (strcmp(token,
"d") == 0) {
143 readGLfloat(&curr->d, 1, &saveptr);
144 }
else if (strcmp(token,
"Ka") == 0) {
145 readGLmaterial( curr->Ka, &saveptr );
146 }
else if (strcmp(token,
"Kd") == 0) {
147 readGLmaterial( curr->Kd, &saveptr );
148 }
else if (strcmp(token,
"Ks") == 0) {
149 readGLmaterial( curr->Ks, &saveptr );
150 }
else if (strcmp(token,
"Ke") == 0) {
151 readGLmaterial( curr->Ke, &saveptr );
152 }
else if (strncmp(token,
"map_", 4) == 0) {
154 if (strcmp(token,
"map_Kd") == 0)
156 else if (strcmp(token,
"map_Ks") == 0)
158 else if (strcmp(token,
"map_Ke") == 0)
160 else if (strcmp(token,
"map_Bump") == 0)
161 map = &curr->map_Bump;
163 LOG(_(
"Can't understand token %s"), token);
166 char *args = SDL_strtokr(NULL,
"\n", &saveptr), *endp;
168 while (isspace(*args))
170 if (strncmp(args,
"-bm", 3) == 0 && isspace(args[3])) {
172 curr->bm = strtof(args, &endp);
173 assert(
"Bad -bm argument" && endp != args);
176 else if (strncmp(args,
"-s", 2) == 0 && isspace(args[2])) {
178 LOG(_(
"-s (texture scaling) option ignored for %s"), token);
181 (void) strtof(args, &endp);
183 while (endp != args);
185 else if (args[0] ==
'-')
186 ERR(_(
"Options not supported for %s"), token);
192 copy_filename = strdup(filename);
193 SDL_asprintf(&texture_filename,
"%s/%s", dirname(copy_filename), args);
196 free(texture_filename);
198 }
else if (strcmp(token,
"Ke") == 0 || strcmp(token,
"illum") == 0) {
200 }
else if (token[0] ==
'#') {
203 LOG(_(
"Can't understand token %s"), token);
206 line = SDL_strtokr(NULL,
"\n", &filesaveptr);
228 char *filebuf, *filesaveptr, *line;
233 ERR(_(
"Cannot open object file %s"), filename);
234 DEBUG(_(
"Loading object file %s"), filename);
239 if (emptyTextureRefs++ == 0) {
240 float zero[]= {0., 0., 0., 0.};
241 float one[] = {1., 1., 1., 1.};
242 zeroTexture = gl_loadImageData( zero, 1, 1, 1, 1,
"solid_zero" );
243 oneTexture = gl_loadImageData( one, 1, 1, 1, 1,
"solid_white" );
250 line = SDL_strtokr(filebuf,
"\n", &filesaveptr);
251 while (line != NULL) {
253 char *saveptr, *copy_filename, *material_filename;
254 token = SDL_strtokr(line, DELIM, &saveptr);
258 }
else if (strcmp(token,
"mtllib") == 0) {
259 while ((token = SDL_strtokr(NULL, DELIM, &saveptr)) != NULL) {
261 copy_filename = strdup(filename);
262 SDL_asprintf(&material_filename,
"%s/%s", dirname(copy_filename), token);
263 materials_readFromFile(material_filename, &object->materials);
265 free(material_filename);
267 }
else if (strcmp(token,
"o") == 0) {
268 mesh_create(&object->meshes, name, corners, material);
269 token = SDL_strtokr(NULL, DELIM, &saveptr);
270 free(name), name = strdup(token);
271 }
else if (strcmp(token,
"v") == 0) {
275 readGLfloat(
array_end(vertex) - 3, 3, &saveptr);
276 }
else if (strcmp(token,
"vt") == 0) {
279 readGLfloat(
array_end(texture) - 2, 2, &saveptr);
280 }
else if (strcmp(token,
"vn") == 0) {
284 readGLfloat(
array_end(normal) - 3, 3, &saveptr);
285 }
else if (strcmp(token,
"f") == 0) {
287 while ((token = SDL_strtokr(NULL, DELIM, &saveptr)) != NULL) {
288 int i_v = 0, i_t = 0, i_n = 0;
289 if (sscanf(token,
"%d//%d", &i_v, &i_n) < 2)
290 sscanf(token,
"%d/%d/%d", &i_v, &i_t, &i_n);
292 assert(
"Vertex index out of range." && (0 < i_v && i_v <=
array_size(vertex) / 3));
293 assert(
"Texture index out of range." && (0 <= i_t && i_t <=
array_size(texture) / 2));
294 assert(
"Normal index out of range." && (0 < i_n && i_n <=
array_size(normal) / 3));
298 memcpy(face->ver, vertex + i_v * 3,
sizeof(GLfloat) * 3);
300 memcpy(face->tex, texture + i_t * 2,
sizeof(GLfloat) * 2);
302 memset(face->tex, 0,
sizeof(GLfloat) * 2);
303 memcpy(face->nor, normal + i_n * 3,
sizeof(GLfloat) * 3);
307 assert(
"Too few or too many vertices for a face." && (num == 3));
308 }
else if (strcmp(token,
"usemtl") == 0) {
309 mesh_create(&object->meshes, name, corners, material);
312 token = SDL_strtokr(NULL, DELIM, &saveptr);
313 for (material = 0; material <
array_size(object->materials); ++material)
314 if (strcmp(token, object->materials[material].name) == 0)
317 if (material ==
array_size(object->materials))
318 ERR(_(
"No such material %s"), token);
319 }
else if (token[0] ==
'#') {
321 }
else if (strcmp(token,
"l") == 0 || strcmp(token,
"s") == 0) {
325 LOG(_(
"Can't understand token %s"), token);
328 line = SDL_strtokr(NULL,
"\n", &filesaveptr);
331 mesh_create(&object->meshes, name, corners, material);
337 object->radius =
MAX( object->radius, v[0]*v[0]+v[1]*v[1]+v[2]*v[2] );
339 object->radius = sqrt( object->radius );
359 for (
int i=0; i <
array_size(object->materials); ++i) {
360 Material *material = &
object->materials[i];
361 free(material->name);
368 for (
int i=0; i <
array_size(object->meshes); ++i) {
369 Mesh *mesh = &
object->meshes[i];
377 if (--emptyTextureRefs == 0) {
380 zeroTexture = oneTexture = NULL;
386static void object_renderMesh(
const Object *
object,
int part, GLfloat alpha )
388 const Mesh *mesh = &
object->meshes[part];
391 const int ver_offset = offsetof(
Vertex, ver);
392 const int tex_offset = offsetof(
Vertex, tex);
393 const int nor_offset = offsetof(
Vertex, nor);
396 glEnableVertexAttribArray(shaders.material.vertex);
398 glEnableVertexAttribArray(shaders.material.vertex_tex);
400 glEnableVertexAttribArray(shaders.material.vertex_normal);
404 assert(
"Part has no material" && (mesh->material != -1));
405 Material *material =
object->materials + mesh->material;
408 glUniform1f(shaders.material.Ns, material->Ns);
409 glUniform3f(shaders.material.Ka, material->Ka[0], material->Ka[1], material->Ka[2] );
410 glUniform3f(shaders.material.Kd, material->Kd[0], material->Kd[1], material->Kd[2] );
411 glUniform3f(shaders.material.Ks, material->Ks[0], material->Ks[1], material->Ks[2] );
412 glUniform3f(shaders.material.Ke, material->Ke[0], material->Ke[1], material->Ke[2] );
413 glUniform1f(shaders.material.Ni, material->Ni);
414 glUniform1f(shaders.material.d, material->d * alpha);
415 glUniform1f(shaders.material.bm, material->bm);
418 glUniform1i(shaders.material.map_Kd, 0);
419 glUniform1i(shaders.material.map_Ks, 1);
420 glUniform1i(shaders.material.map_Ke, 2);
421 glUniform1i(shaders.material.map_Bump, 3);
422 glActiveTexture(GL_TEXTURE3);
423 glBindTexture(GL_TEXTURE_2D, material->map_Bump == NULL ? zeroTexture->
texture : material->map_Bump->
texture);
424 glActiveTexture(GL_TEXTURE2);
425 glBindTexture(GL_TEXTURE_2D, material->map_Ke == NULL ? oneTexture->
texture : material->map_Ke->
texture);
426 glActiveTexture(GL_TEXTURE1);
427 glBindTexture(GL_TEXTURE_2D, material->map_Ks == NULL ? oneTexture->
texture : material->map_Ks->
texture);
429 glActiveTexture(GL_TEXTURE0);
430 glBindTexture(GL_TEXTURE_2D, material->map_Kd == NULL ? oneTexture->
texture : material->map_Kd->
texture);
432 glDrawArrays(GL_TRIANGLES, 0, mesh->num_corners);
435void object_renderSolidPart(
const Object *
object,
const Solid *solid,
const char *part_name, GLfloat alpha,
double scale )
437 mat4 view, projection, model, ortho;
453 glUseProgram(shaders.material.program);
457 ortho =
mat4_ortho(-os, os, -os, os, od, -od);
458 mat4_mul( &view, &projection, &ortho );
464 gl_uniformMat4(shaders.material.projection, &view);
465 gl_uniformMat4(shaders.material.model, &model);
468 glEnable(GL_DEPTH_TEST);
469 glDepthFunc(GL_LESS);
470 glClear( GL_DEPTH_BUFFER_BIT );
472 for (
int i=0; i <
array_size(object->meshes); ++i)
473 if (strcmp(part_name, object->meshes[i].name) == 0)
474 object_renderMesh(
object, i, alpha);
477 glDisable(GL_DEPTH_TEST);
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
#define array_resize(ptr_array, new_size)
Resizes the array to accomodate new_size elements.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
#define array_back(ptr_array)
Returns the last element in the array.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
void mat4_translate(mat4 *m, double x, double y, double z)
Translates a homogenous transformation matrix.
mat4 mat4_identity(void)
Creates an identity matrix.
void mat4_rotate(mat4 *m, double angle, double x, double y, double z)
Multiplies the given matrix by a rotation. (Follows the right-hand rule.)
void mat4_mul(mat4 *out, const mat4 *m1, const mat4 *m2)
Multiplies two matrices (out = m1 * m2).
mat4 mat4_ortho(double left, double right, double bottom, double top, double nearVal, double farVal)
Creates an orthographic projection matrix.
Header file with generic functions and naev-specifics.
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
void object_free(Object *object)
Frees memory reserved for the object.
Object * object_loadFromFile(const char *filename)
Loads object.
mat4 gl_gameToScreenMatrix(mat4 lhs)
Return a transformation which converts in-game coordinates to screen coordinates.
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
void gl_freeTexture(glTexture *texture)
Frees a texture.
void gl_vboDestroy(gl_vbo *vbo)
Destroys a VBO.
void gl_vboActivateAttribOffset(gl_vbo *vbo, GLuint index, GLuint offset, GLint size, GLenum type, GLsizei stride)
Activates a VBO's offset.
gl_vbo * gl_vboCreateStatic(GLsizei size, const void *data)
Creates a stream vbo.
Represents a solid in the game.
Reference to a spob or jump point.
Abstraction for rendering sprite sheets.