28#if defined(_WIN32) || defined(_WIN64)
29# define strtok_r strtok_s
33#define NAEV_ORTHO_SCALE 10.
34#define NAEV_ORTHO_DIST 9.*M_SQRT2
36typedef struct Material_ {
38 GLfloat Ka[3], Kd[3], Ks[3], Ke[3];
39 GLfloat Ns, Ni,
d, bm;
40 glTexture *map_Kd, *map_Ks, *map_Ke, *map_Bump;
50typedef struct Object_ {
64static unsigned int emptyTextureRefs= 0;
66static void mesh_create(
Mesh **meshes,
const char* name,
67 Vertex *corners,
int material )
72 ERR(_(
"No name for current part"));
74 ERR(_(
"No material for current part"));
77 mesh->name = strdup(name);
80 mesh->material = material;
84static int readGLfloat( GLfloat *dest,
int how_many,
char **saveptr )
89 while ((token = strtok_r(NULL, DELIM, saveptr)) != NULL) {
91 sscanf(token,
"%lf", &
d);
92 assert(num <= how_many);
96 assert(num == how_many);
100static int readGLmaterial( GLfloat col[3],
char **saveptr )
102 int ret = readGLfloat( col, 3, saveptr );
112static void materials_readFromFile(
const char *filename,
Material **materials )
114 char *filebuf, *filesaveptr, *line;
116 DEBUG(_(
"Loading material from %s"), filename);
120 ERR(_(
"Cannot open object file %s"), filename);
124 line = strtok_r(filebuf,
"\n", &filesaveptr);
125 while (line != NULL) {
127 char *saveptr, *copy_filename, *texture_filename;
128 token = strtok_r(line, DELIM, &saveptr);
132 }
else if (strcmp(token,
"newmtl") == 0) {
133 token = strtok_r(NULL, DELIM, &saveptr);
135 curr->name = strdup(token);
140 curr->map_Kd = curr->map_Ks = curr->map_Ke = curr->map_Bump = NULL;
141 DEBUG(_(
"Reading new material %s"), curr->name);
142 }
else if (strcmp(token,
"Ns") == 0) {
143 readGLfloat(&curr->Ns, 1, &saveptr);
144 }
else if (strcmp(token,
"Ni") == 0) {
145 readGLfloat(&curr->Ni, 1, &saveptr);
146 }
else if (strcmp(token,
"d") == 0) {
147 readGLfloat(&curr->d, 1, &saveptr);
148 }
else if (strcmp(token,
"Ka") == 0) {
149 readGLmaterial( curr->Ka, &saveptr );
150 }
else if (strcmp(token,
"Kd") == 0) {
151 readGLmaterial( curr->Kd, &saveptr );
152 }
else if (strcmp(token,
"Ks") == 0) {
153 readGLmaterial( curr->Ks, &saveptr );
154 }
else if (strcmp(token,
"Ke") == 0) {
155 readGLmaterial( curr->Ke, &saveptr );
156 }
else if (strncmp(token,
"map_", 4) == 0) {
158 if (strcmp(token,
"map_Kd") == 0)
160 else if (strcmp(token,
"map_Ks") == 0)
162 else if (strcmp(token,
"map_Ke") == 0)
164 else if (strcmp(token,
"map_Bump") == 0)
165 map = &curr->map_Bump;
167 LOG(_(
"Can't understand token %s"), token);
170 char *args = strtok_r(NULL,
"\n", &saveptr), *endp;
172 while (isspace(*args))
174 if (strncmp(args,
"-bm", 3) == 0 && isspace(args[3])) {
176 curr->bm = strtof(args, &endp);
177 assert(
"Bad -bm argument" && endp != args);
180 else if (strncmp(args,
"-s", 2) == 0 && isspace(args[2])) {
182 LOG(_(
"-s (texture scaling) option ignored for %s"), token);
185 (void) strtof(args, &endp);
187 while (endp != args);
189 else if (args[0] ==
'-')
190 ERR(_(
"Options not supported for %s"), token);
196 copy_filename = strdup(filename);
197 asprintf(&texture_filename,
"%s/%s", dirname(copy_filename), args);
200 free(texture_filename);
202 }
else if (strcmp(token,
"Ke") == 0 || strcmp(token,
"illum") == 0) {
204 }
else if (token[0] ==
'#') {
207 LOG(_(
"Can't understand token %s"), token);
210 line = strtok_r(NULL,
"\n", &filesaveptr);
232 char *filebuf, *filesaveptr, *line;
237 ERR(_(
"Cannot open object file %s"), filename);
238 DEBUG(_(
"Loading object file %s"), filename);
243 if (emptyTextureRefs++ == 0) {
244 float zero[]= {0., 0., 0., 0.};
245 float one[] = {1., 1., 1., 1.};
246 zeroTexture = gl_loadImageData( zero, 1, 1, 1, 1,
"solid_zero" );
247 oneTexture = gl_loadImageData( one, 1, 1, 1, 1,
"solid_white" );
254 line = strtok_r(filebuf,
"\n", &filesaveptr);
255 while (line != NULL) {
257 char *saveptr, *copy_filename, *material_filename;
258 token = strtok_r(line, DELIM, &saveptr);
262 }
else if (strcmp(token,
"mtllib") == 0) {
263 while ((token = strtok_r(NULL, DELIM, &saveptr)) != NULL) {
265 copy_filename = strdup(filename);
266 asprintf(&material_filename,
"%s/%s", dirname(copy_filename), token);
267 materials_readFromFile(material_filename, &object->materials);
269 free(material_filename);
271 }
else if (strcmp(token,
"o") == 0) {
272 mesh_create(&object->meshes, name, corners, material);
273 token = strtok_r(NULL, DELIM, &saveptr);
274 free(name), name = strdup(token);
275 }
else if (strcmp(token,
"v") == 0) {
279 readGLfloat(
array_end(vertex) - 3, 3, &saveptr);
280 }
else if (strcmp(token,
"vt") == 0) {
283 readGLfloat(
array_end(texture) - 2, 2, &saveptr);
284 }
else if (strcmp(token,
"vn") == 0) {
288 readGLfloat(
array_end(normal) - 3, 3, &saveptr);
289 }
else if (strcmp(token,
"f") == 0) {
291 while ((token = strtok_r(NULL, DELIM, &saveptr)) != NULL) {
292 int i_v = 0, i_t = 0, i_n = 0;
293 if (sscanf(token,
"%d//%d", &i_v, &i_n) < 2)
294 sscanf(token,
"%d/%d/%d", &i_v, &i_t, &i_n);
296 assert(
"Vertex index out of range." && (0 < i_v && i_v <=
array_size(vertex) / 3));
297 assert(
"Texture index out of range." && (0 <= i_t && i_t <=
array_size(texture) / 2));
298 assert(
"Normal index out of range." && (0 < i_n && i_n <=
array_size(normal) / 3));
302 memcpy(face->ver, vertex + i_v * 3,
sizeof(GLfloat) * 3);
304 memcpy(face->tex, texture + i_t * 2,
sizeof(GLfloat) * 2);
306 memset(face->tex, 0,
sizeof(GLfloat) * 2);
307 memcpy(face->nor, normal + i_n * 3,
sizeof(GLfloat) * 3);
311 assert(
"Too few or too many vertices for a face." && (num == 3));
312 }
else if (strcmp(token,
"usemtl") == 0) {
313 mesh_create(&object->meshes, name, corners, material);
316 token = strtok_r(NULL, DELIM, &saveptr);
317 for (material = 0; material <
array_size(object->materials); ++material)
318 if (strcmp(token, object->materials[material].name) == 0)
321 if (material ==
array_size(object->materials))
322 ERR(_(
"No such material %s"), token);
323 }
else if (token[0] ==
'#') {
325 }
else if (strcmp(token,
"l") == 0 || strcmp(token,
"s") == 0) {
329 LOG(_(
"Can't understand token %s"), token);
332 line = strtok_r(NULL,
"\n", &filesaveptr);
335 mesh_create(&object->meshes, name, corners, material);
341 object->radius =
MAX( object->radius, v[0]*v[0]+v[1]*v[1]+v[2]*v[2] );
343 object->radius = sqrt( object->radius );
363 for (
int i=0; i <
array_size(object->materials); ++i) {
364 Material *material = &
object->materials[i];
365 free(material->name);
372 for (
int i=0; i <
array_size(object->meshes); ++i) {
373 Mesh *mesh = &
object->meshes[i];
381 if (--emptyTextureRefs == 0) {
384 zeroTexture = oneTexture = NULL;
390static void object_renderMesh(
const Object *
object,
int part, GLfloat alpha )
392 const Mesh *mesh = &
object->meshes[part];
395 const int ver_offset = offsetof(
Vertex, ver);
396 const int tex_offset = offsetof(
Vertex, tex);
397 const int nor_offset = offsetof(
Vertex, nor);
400 glEnableVertexAttribArray(shaders.material.vertex);
402 glEnableVertexAttribArray(shaders.material.vertex_tex);
404 glEnableVertexAttribArray(shaders.material.vertex_normal);
408 assert(
"Part has no material" && (mesh->material != -1));
409 Material *material =
object->materials + mesh->material;
412 glUniform1f(shaders.material.Ns, material->Ns);
413 glUniform3f(shaders.material.Ka, material->Ka[0], material->Ka[1], material->Ka[2] );
414 glUniform3f(shaders.material.Kd, material->Kd[0], material->Kd[1], material->Kd[2] );
415 glUniform3f(shaders.material.Ks, material->Ks[0], material->Ks[1], material->Ks[2] );
416 glUniform3f(shaders.material.Ke, material->Ke[0], material->Ke[1], material->Ke[2] );
417 glUniform1f(shaders.material.Ni, material->Ni);
418 glUniform1f(shaders.material.d, material->d * alpha);
419 glUniform1f(shaders.material.bm, material->bm);
422 glUniform1i(shaders.material.map_Kd, 0);
423 glUniform1i(shaders.material.map_Ks, 1);
424 glUniform1i(shaders.material.map_Ke, 2);
425 glUniform1i(shaders.material.map_Bump, 3);
426 glActiveTexture(GL_TEXTURE3);
427 glBindTexture(GL_TEXTURE_2D, material->map_Bump == NULL ? zeroTexture->
texture : material->map_Bump->
texture);
428 glActiveTexture(GL_TEXTURE2);
429 glBindTexture(GL_TEXTURE_2D, material->map_Ke == NULL ? oneTexture->
texture : material->map_Ke->
texture);
430 glActiveTexture(GL_TEXTURE1);
431 glBindTexture(GL_TEXTURE_2D, material->map_Ks == NULL ? oneTexture->
texture : material->map_Ks->
texture);
433 glActiveTexture(GL_TEXTURE0);
434 glBindTexture(GL_TEXTURE_2D, material->map_Kd == NULL ? oneTexture->
texture : material->map_Kd->
texture);
436 glDrawArrays(GL_TRIANGLES, 0, mesh->num_corners);
439void object_renderSolidPart(
const Object *
object,
const Solid *solid,
const char *part_name, GLfloat alpha,
double scale )
441 mat4 view, projection, model, ortho;
457 glUseProgram(shaders.material.program);
461 ortho =
mat4_ortho(-os, os, -os, os, od, -od);
462 mat4_mul( &view, &projection, &ortho );
468 gl_uniformMat4(shaders.material.projection, &view);
469 gl_uniformMat4(shaders.material.model, &model);
472 glEnable(GL_DEPTH_TEST);
473 glDepthFunc(GL_LESS);
474 glClear( GL_DEPTH_BUFFER_BIT );
476 for (
int i=0; i <
array_size(object->meshes); ++i)
477 if (strcmp(part_name, object->meshes[i].name) == 0)
478 object_renderMesh(
object, i, alpha);
481 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).
int asprintf(char **strp, const char *fmt,...)
Like sprintf(), but it allocates a large-enough string and returns the pointer in the first argument....
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.