taisei/src/resource/model.c

262 lines
5.9 KiB
C
Raw Normal View History

2012-07-15 08:15:47 +02:00
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
2012-07-15 08:15:47 +02:00
* ---
2018-01-04 18:14:31 +01:00
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
2012-07-15 08:15:47 +02:00
*/
#include "taisei.h"
2012-07-15 08:15:47 +02:00
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "model.h"
#include "list.h"
#include "resource.h"
#include "renderer/api.h"
ResourceHandler model_res_handler = {
.type = RES_MODEL,
.typename = "model",
.subdir = MDL_PATH_PREFIX,
.procs = {
.find = model_path,
.check = check_model_path,
.begin_load = load_model_begin,
.end_load = load_model_end,
.unload = unload_model,
},
};
static void parse_obj(const char *filename, ObjFileData *data);
static void free_obj(ObjFileData *data);
char* model_path(const char *name) {
return strjoin(MDL_PATH_PREFIX, name, MDL_EXTENSION, NULL);
}
bool check_model_path(const char *path) {
return strendswith(path, MDL_EXTENSION);
}
2017-03-13 06:44:39 +01:00
typedef struct ModelLoadData {
ObjFileData *obj;
GenericModelVertex *verts;
2017-03-13 06:44:39 +01:00
Model *model;
} ModelLoadData;
void* load_model_begin(const char *path, uint flags) {
2017-03-13 06:44:39 +01:00
Model *m = malloc(sizeof(Model));
ObjFileData *data = malloc(sizeof(ObjFileData));
GenericModelVertex *verts;
2017-03-13 06:44:39 +01:00
parse_obj(path, data);
2017-03-13 06:44:39 +01:00
m->fverts = data->fverts;
m->indices = calloc(data->icount, sizeof(uint));
2017-03-13 06:44:39 +01:00
m->icount = data->icount;
verts = calloc(data->icount, sizeof(GenericModelVertex));
2017-03-13 06:44:39 +01:00
#define BADREF(filename,aux,n) { \
log_warn("OBJ file '%s': Index %d: bad %s index reference\n", filename, n, aux); \
goto fail; \
2017-03-13 06:44:39 +01:00
}
memset(verts, 0, data->icount*sizeof(GenericModelVertex));
for(uint i = 0; i < data->icount; i++) {
int xi, ni, ti;
2017-03-13 06:44:39 +01:00
xi = data->indices[i][0]-1;
if(xi < 0 || xi >= data->xcount)
BADREF(path, "vertex", i);
memcpy(verts[i].position, data->xs[xi], sizeof(vec3_noalign));
2017-03-13 06:44:39 +01:00
if(data->tcount) {
ti = data->indices[i][1]-1;
if(ti < 0 || ti >= data->tcount)
BADREF(path, "texcoord", i);
verts[i].uv.s = data->texcoords[ti][0];
verts[i].uv.t = data->texcoords[ti][1];
}
2017-03-13 06:44:39 +01:00
if(data->ncount) {
ni = data->indices[i][2]-1;
if(ni < 0 || ni >= data->ncount)
BADREF(path, "normal", ni);
memcpy(verts[i].normal, data->normals[ni], sizeof(vec3_noalign));
}
2017-03-13 06:44:39 +01:00
m->indices[i] = i;
}
#undef BADREF
2017-03-13 06:44:39 +01:00
ModelLoadData *ldata = malloc(sizeof(ModelLoadData));
ldata->obj = data;
ldata->verts = verts;
ldata->model = m;
return ldata;
fail:
free(m->indices);
free(m);
free(verts);
free_obj(data);
free(data);
return NULL;
2017-03-13 06:44:39 +01:00
}
void* load_model_end(void *opaque, const char *path, uint flags) {
VertexBuffer *vbuf= r_vertex_buffer_static_models();
2017-03-13 06:44:39 +01:00
ModelLoadData *ldata = opaque;
if(!ldata) {
return NULL;
}
OpenGL ES 3.0 rendering backend (#148) * First steps towards shader transpilation Needs to be manually enabled via -Dshader_transpiler=true. Requires shaderc. https://github.com/google/shaderc Not yet functional due to missing SPIRV-Cross integration. SPIRV-Cross currently does not have an official C API, and crossc is too minimal to be useful. The current plan is to extend crossc and vendor it, while also sending PRs upstream. * Integrate crossc; shader transpilation for GLES now works * fix leak * gles30 backend now playable on Mesa with 3.2 context Some rendering issues are present. Identified so far: - Marisa's lasers are invisible - Death effect looks wrong Also, a small pixmap manipulation library has been written, and the texture uploading API redesigned around it. * fix marisa lasers in GLES (uniform name clashed with builtin) * fix player death effect in GLES (another name clash) * Dump ANGLE's translated shader code in debug log * fix screenshots * Drop support for triangle fans, switch to strips Fans offer no advantage over strips, and they've been removed in D3D10+, so ANGLE has to emulate them. * crude workaround for an ANGLE bug * Re-enable GL debug labels, fix an issue with them that affected ANGLE (but was always technically a bug) * fix race condition in shaderc initialization * New SDL_RWops interface for vertex buffers * Optimize VBO streaming via buffering updates Measurable performance improvement even with the main gl33 renderer, drastic improvement with ANGLE. * Fix the depth texture binding problem under ANGLE Apparently it hates GL_DEPTH_COMPONENT16 for some reason. Sized internal formats are not supported in GLES 2.0 anyway, so not using them is probably a good idea. * fix GLES2.0 segfault (the backend still doesn't work, though) * dump GL extensions at info log level, not debug * get around a Mesa bug; more correct texture format table for GLES2 * Correct GLES3 texture format table according to the spec Not a Mesa bug after all * require crossc>=1.5.0, fallback to subproject * Request at least 8bit per color channel in GL backends * Forbid lto for static windows builds with shader_transpiler=true * fix edge case segfault * Add basic ANGLE bundling support to the build system Windows only, and no NSIS support yet * Fix various windows-related build system and installer brokenness * Disable gles backends by default * update documentation
2018-10-02 00:36:10 +02:00
SDL_RWops *stream = r_vertex_buffer_get_stream(vbuf);
size_t ioffset = SDL_RWtell(stream);
2017-03-13 06:44:39 +01:00
for(int i = 0; i < ldata->obj->icount; ++i) {
ldata->model->indices[i] += ioffset / sizeof(GenericModelVertex);
2017-03-13 06:44:39 +01:00
}
OpenGL ES 3.0 rendering backend (#148) * First steps towards shader transpilation Needs to be manually enabled via -Dshader_transpiler=true. Requires shaderc. https://github.com/google/shaderc Not yet functional due to missing SPIRV-Cross integration. SPIRV-Cross currently does not have an official C API, and crossc is too minimal to be useful. The current plan is to extend crossc and vendor it, while also sending PRs upstream. * Integrate crossc; shader transpilation for GLES now works * fix leak * gles30 backend now playable on Mesa with 3.2 context Some rendering issues are present. Identified so far: - Marisa's lasers are invisible - Death effect looks wrong Also, a small pixmap manipulation library has been written, and the texture uploading API redesigned around it. * fix marisa lasers in GLES (uniform name clashed with builtin) * fix player death effect in GLES (another name clash) * Dump ANGLE's translated shader code in debug log * fix screenshots * Drop support for triangle fans, switch to strips Fans offer no advantage over strips, and they've been removed in D3D10+, so ANGLE has to emulate them. * crude workaround for an ANGLE bug * Re-enable GL debug labels, fix an issue with them that affected ANGLE (but was always technically a bug) * fix race condition in shaderc initialization * New SDL_RWops interface for vertex buffers * Optimize VBO streaming via buffering updates Measurable performance improvement even with the main gl33 renderer, drastic improvement with ANGLE. * Fix the depth texture binding problem under ANGLE Apparently it hates GL_DEPTH_COMPONENT16 for some reason. Sized internal formats are not supported in GLES 2.0 anyway, so not using them is probably a good idea. * fix GLES2.0 segfault (the backend still doesn't work, though) * dump GL extensions at info log level, not debug * get around a Mesa bug; more correct texture format table for GLES2 * Correct GLES3 texture format table according to the spec Not a Mesa bug after all * require crossc>=1.5.0, fallback to subproject * Request at least 8bit per color channel in GL backends * Forbid lto for static windows builds with shader_transpiler=true * fix edge case segfault * Add basic ANGLE bundling support to the build system Windows only, and no NSIS support yet * Fix various windows-related build system and installer brokenness * Disable gles backends by default * update documentation
2018-10-02 00:36:10 +02:00
SDL_RWwrite(stream, ldata->verts, sizeof(GenericModelVertex), ldata->obj->icount);
2017-03-13 06:44:39 +01:00
free(ldata->verts);
free_obj(ldata->obj);
free(ldata->obj);
Model *m = ldata->model;
free(ldata);
return m;
}
void unload_model(void *model) { // Does not delete elements from the VBO, so doing this at runtime is leaking VBO space
free(((Model*)model)->indices);
free(model);
}
static void free_obj(ObjFileData *data) {
free(data->xs);
free(data->normals);
free(data->texcoords);
free(data->indices);
}
2017-02-28 18:47:47 +01:00
static void parse_obj(const char *filename, ObjFileData *data) {
2017-04-18 21:48:18 +02:00
SDL_RWops *rw = vfs_open(filename, VFS_MODE_READ);
2017-03-12 22:22:43 +01:00
if(!rw) {
2017-04-18 21:48:18 +02:00
log_warn("VFS error: %s", vfs_get_error());
2017-03-12 22:22:43 +01:00
return;
}
2017-03-13 06:44:39 +01:00
char line[256], *save;
vec3_noalign buf;
2012-07-15 08:15:47 +02:00
char mode;
int linen = 0;
2012-07-15 08:15:47 +02:00
memset(data, 0, sizeof(ObjFileData));
2017-03-12 22:22:43 +01:00
while(SDL_RWgets(rw, line, sizeof(line))) {
2012-07-15 08:15:47 +02:00
linen++;
2012-07-15 08:15:47 +02:00
char *first;
2017-03-13 06:44:39 +01:00
first = strtok_r(line, " \n", &save);
2012-07-15 08:15:47 +02:00
if(strcmp(first, "v") == 0)
mode = 'v';
else if(strcmp(first, "vt") == 0)
mode = 't';
else if(strcmp(first, "vn") == 0)
mode = 'n';
else if(strcmp(first, "f") == 0)
mode = 'f';
else
mode = 0;
if(mode != 0 && mode != 'f') {
2017-03-13 06:44:39 +01:00
buf[0] = atof(strtok_r(NULL, " \n", &save));
char *wtf = strtok_r(NULL, " \n", &save);
buf[1] = atof(wtf);
2012-07-15 08:15:47 +02:00
if(mode != 't')
2017-03-13 06:44:39 +01:00
buf[2] = atof(strtok_r(NULL, " \n", &save));
2012-07-15 08:15:47 +02:00
switch(mode) {
case 'v':
data->xs = realloc(data->xs, sizeof(vec3_noalign)*(++data->xcount));
memcpy(data->xs[data->xcount-1], buf, sizeof(vec3_noalign));
2012-07-15 08:15:47 +02:00
break;
case 't':
data->texcoords = realloc(data->texcoords, sizeof(vec3_noalign)*(++data->tcount));
memcpy(data->texcoords[data->tcount-1], buf, sizeof(vec3_noalign));
2012-07-15 08:15:47 +02:00
break;
case 'n':
data->normals = realloc(data->normals, sizeof(vec3_noalign)*(++data->ncount));
memcpy(data->normals[data->ncount-1], buf, sizeof(vec3_noalign));
2012-07-15 08:15:47 +02:00
break;
}
} else if(mode == 'f') {
char *segment, *seg;
int j = 0, jj;
ivec3_noalign ibuf;
2012-07-15 08:15:47 +02:00
memset(ibuf, 0, sizeof(ibuf));
2017-03-13 06:44:39 +01:00
while((segment = strtok_r(NULL, " \n", &save))) {
2012-07-18 13:42:04 +02:00
seg = segment;
j++;
2012-07-15 08:15:47 +02:00
jj = 0;
2012-07-18 13:42:04 +02:00
while(jj < 3) {
2012-07-15 08:15:47 +02:00
ibuf[jj] = atoi(seg);
jj++;
2012-07-18 13:42:04 +02:00
while(*seg != '\0' && *(++seg) != '/');
2012-07-18 13:42:04 +02:00
if(*seg == '\0')
break;
else
seg++;
2012-07-15 08:15:47 +02:00
}
2012-07-15 08:15:47 +02:00
if(strstr(segment, "//")) {
ibuf[2] = ibuf[1];
ibuf[1] = 0;
}
2012-07-15 08:15:47 +02:00
if(jj == 0 || jj > 3 || segment[0] == '/')
2017-03-13 17:03:51 +01:00
log_fatal("OBJ file '%s:%d': Parsing error: Corrupt face definition", filename,linen);
data->indices = realloc(data->indices, sizeof(ivec3_noalign)*(++data->icount));
memcpy(data->indices[data->icount-1], ibuf, sizeof(ivec3_noalign));
2012-07-15 08:15:47 +02:00
}
2012-07-18 13:42:04 +02:00
2012-07-15 08:15:47 +02:00
if(data->fverts == 0)
data->fverts = j;
2012-07-15 08:15:47 +02:00
if(data->fverts != j)
2017-03-13 17:03:51 +01:00
log_fatal("OBJ file '%s:%d': Parsing error: face vertex count must stay the same in the whole file", filename, linen);
if(data->fverts != 3)
log_fatal("OBJ file '%s:%d': Parsing error: face vertex count must be 3", filename, linen);
2012-07-15 08:15:47 +02:00
}
}
2017-03-12 22:22:43 +01:00
SDL_RWclose(rw);
2012-07-15 08:15:47 +02:00
}
Model* get_model(const char *name) {
return get_resource(RES_MODEL, name, RESF_DEFAULT)->data;
2012-07-15 08:15:47 +02:00
}