nuclear@16: #include nuclear@16: #include nuclear@16: #include "goat3d.h" nuclear@16: #include "goat3d_impl.h" nuclear@16: #include "log.h" nuclear@16: nuclear@16: struct goat3d { nuclear@16: Scene *scn; nuclear@16: unsigned int flags; nuclear@16: }; nuclear@16: nuclear@16: struct goat3d_material : public Material {}; nuclear@16: struct goat3d_mesh : public Mesh {}; nuclear@16: struct goat3d_light : public Light {}; nuclear@16: struct goat3d_camera : public Camera {}; nuclear@16: struct goat3d_node : public Node {}; nuclear@16: nuclear@16: nuclear@16: static long read_file(void *buf, size_t bytes, void *uptr); nuclear@16: static long write_file(const void *buf, size_t bytes, void *uptr); nuclear@16: static long seek_file(long offs, int whence, void *uptr); nuclear@16: nuclear@16: extern "C" { nuclear@16: nuclear@16: struct goat3d *goat3d_create(void) nuclear@16: { nuclear@16: goat3d *goat = new goat3d; nuclear@16: goat->scn = new Scene; nuclear@16: return goat; nuclear@16: } nuclear@16: nuclear@16: void goat3d_free(struct goat3d *g) nuclear@16: { nuclear@16: delete g->scn; nuclear@16: delete g; nuclear@16: } nuclear@16: nuclear@16: void goat3d_setopt(struct goat3d *g, enum goat3d_option opt, int val) nuclear@16: { nuclear@16: if(val) { nuclear@16: g->flags |= (1 << (int)opt); nuclear@16: } else { nuclear@16: g->flags &= ~(1 << (int)opt); nuclear@16: } nuclear@16: } nuclear@16: nuclear@16: int goat3d_getopt(const struct goat3d *g, enum goat3d_option opt) nuclear@16: { nuclear@16: return (g->flags >> (int)opt) & 1; nuclear@16: } nuclear@16: nuclear@16: int goat3d_load(struct goat3d *g, const char *fname) nuclear@16: { nuclear@16: FILE *fp = fopen(fname, "rb"); nuclear@16: if(!fp) { nuclear@16: logmsg(LOG_ERROR, "failed to open file \"%s\" for reading: %s\n", fname, strerror(errno)); nuclear@16: return -1; nuclear@16: } nuclear@16: nuclear@16: int res = goat3d_load_file(g, fp); nuclear@16: fclose(fp); nuclear@16: return res; nuclear@16: } nuclear@16: nuclear@16: int goat3d_save(const struct goat3d *g, const char *fname) nuclear@16: { nuclear@16: FILE *fp = fopen(fname, "wb"); nuclear@16: if(!fp) { nuclear@16: logmsg(LOG_ERROR, "failed to open file \"%s\" for writing: %s\n", fname, strerror(errno)); nuclear@16: return -1; nuclear@16: } nuclear@16: nuclear@16: int res = goat3d_save_file(g, fp); nuclear@16: fclose(fp); nuclear@16: return res; nuclear@16: } nuclear@16: nuclear@16: int goat3d_load_file(struct goat3d *g, FILE *fp) nuclear@16: { nuclear@16: goat3d_io io; nuclear@16: io.cls = fp; nuclear@16: io.read = read_file; nuclear@16: io.write = write_file; nuclear@16: io.seek = seek_file; nuclear@16: nuclear@16: return goat3d_load_io(g, &io); nuclear@16: } nuclear@16: nuclear@16: int goat3d_save_file(const struct goat3d *g, FILE *fp) nuclear@16: { nuclear@16: goat3d_io io; nuclear@16: io.cls = fp; nuclear@16: io.read = read_file; nuclear@16: io.write = write_file; nuclear@16: io.seek = seek_file; nuclear@16: nuclear@16: return goat3d_save_io(g, &io); nuclear@16: } nuclear@16: nuclear@16: int goat3d_load_io(struct goat3d *g, struct goat3d_io *io) nuclear@16: { nuclear@16: if(!g->scn->load(io)) { nuclear@16: if(g->scn->loadxml(io)) { nuclear@16: return -1; nuclear@16: } nuclear@16: } nuclear@16: return 0; nuclear@16: } nuclear@16: nuclear@16: int goat3d_save_io(const struct goat3d *g, struct goat3d_io *io) nuclear@16: { nuclear@16: if(goat3d_getopt(g, GOAT3D_OPT_SAVEXML)) { nuclear@16: return g->scn->savexml(io) ? 0 : -1; nuclear@16: } nuclear@16: return g->scn->save(io) ? 0 : -1; nuclear@16: } nuclear@16: nuclear@16: int goat3d_set_name(struct goat3d *g, const char *name) nuclear@16: { nuclear@16: g->scn->set_name(name); nuclear@16: return 0; nuclear@16: } nuclear@16: nuclear@16: const char *goat3d_get_name(const struct goat3d *g) nuclear@16: { nuclear@16: return g->scn->get_name(); nuclear@16: } nuclear@16: nuclear@16: void goat3d_set_ambient(struct goat3d *g, const float *amb) nuclear@16: { nuclear@16: g->scn->set_ambient(Vector3(amb[0], amb[1], amb[2])); nuclear@16: } nuclear@16: nuclear@16: void goat3d_set_ambient3f(struct goat3d *g, float ar, float ag, float ab) nuclear@16: { nuclear@16: g->scn->set_ambient(Vector3(ar, ag, ab)); nuclear@16: } nuclear@16: nuclear@16: const float *goat3d_get_ambient(const struct goat3d *g) nuclear@16: { nuclear@16: return &g->scn->get_ambient().x; nuclear@16: } nuclear@16: nuclear@16: // ---- materials ---- nuclear@16: struct goat3d_material *goat3d_create_mtl(void) nuclear@16: { nuclear@16: return new goat3d_material; nuclear@16: } nuclear@16: nuclear@16: void goat3d_destroy_mtl(struct goat3d_material *mtl) nuclear@16: { nuclear@16: delete mtl; nuclear@16: } nuclear@16: nuclear@16: void goat3d_set_mtl_name(struct goat3d_material *mtl, const char *name) nuclear@16: { nuclear@16: mtl->name = std::string(name); nuclear@16: } nuclear@16: nuclear@16: const char *goat3d_get_mtl_name(const struct goat3d_material *mtl) nuclear@16: { nuclear@16: return mtl->name.c_str(); nuclear@16: } nuclear@16: nuclear@16: void goat3d_set_mtl_attrib(struct goat3d_material *mtl, const char *attrib, const float *val) nuclear@16: { nuclear@16: (*mtl)[attrib].value = Vector4(val[0], val[1], val[2], val[3]); nuclear@16: } nuclear@16: nuclear@16: void goat3d_set_mtl_attrib1f(struct goat3d_material *mtl, const char *attrib, float val) nuclear@16: { nuclear@16: goat3d_set_mtl_attrib4f(mtl, attrib, val, 0, 0, 1); nuclear@16: } nuclear@16: nuclear@16: void goat3d_set_mtl_attrib3f(struct goat3d_material *mtl, const char *attrib, float r, float g, float b) nuclear@16: { nuclear@16: goat3d_set_mtl_attrib4f(mtl, attrib, r, g, b, 1); nuclear@16: } nuclear@16: nuclear@16: void goat3d_set_mtl_attrib4f(struct goat3d_material *mtl, const char *attrib, float r, float g, float b, float a) nuclear@16: { nuclear@16: (*mtl)[attrib].value = Vector4(r, g, b, a); nuclear@16: } nuclear@16: nuclear@16: const float *goat3d_get_mtl_attrib(struct goat3d_material *mtl, const char *attrib) nuclear@16: { nuclear@16: return &(*mtl)[attrib].value.x; nuclear@16: } nuclear@16: nuclear@16: void goat3d_set_mtl_attrib_map(struct goat3d_material *mtl, const char *attrib, const char *mapname) nuclear@16: { nuclear@16: (*mtl)[attrib].map = std::string(mapname); nuclear@16: } nuclear@16: nuclear@16: const char *goat3d_get_mtl_attrib_map(struct goat3d_material *mtl, const char *attrib) nuclear@16: { nuclear@16: return (*mtl)[attrib].map.c_str(); nuclear@16: } nuclear@16: nuclear@16: void goat3d_add_mtl(struct goat3d *g, struct goat3d_material *mtl) nuclear@16: { nuclear@16: g->scn->add_material(mtl); nuclear@16: } nuclear@16: nuclear@16: // ---- meshes ---- nuclear@16: struct goat3d_mesh *goat3d_create_mesh(void) nuclear@16: { nuclear@16: return new goat3d_mesh; nuclear@16: } nuclear@16: nuclear@16: void goat3d_destroy_mesh(struct goat3d_mesh *mesh) nuclear@16: { nuclear@16: delete mesh; nuclear@16: } nuclear@16: nuclear@16: void goat3d_set_mesh_name(struct goat3d_mesh *mesh, const char *name) nuclear@16: { nuclear@16: mesh->name = std::string(name); nuclear@16: } nuclear@16: nuclear@16: const char *goat3d_get_mesh_name(const struct goat3d_mesh *mesh) nuclear@16: { nuclear@16: return mesh->name.c_str(); nuclear@16: } nuclear@16: nuclear@16: void goat3d_set_mesh_mtl(struct goat3d_mesh *mesh, struct goat3d_material *mtl) nuclear@16: { nuclear@16: mesh->material = mtl; nuclear@16: } nuclear@16: nuclear@16: struct goat3d_material *goat3d_get_mesh_mtl(struct goat3d_mesh *mesh) nuclear@16: { nuclear@16: return (goat3d_material*)mesh->material; nuclear@16: } nuclear@16: nuclear@16: int goat3d_get_mesh_attrib_count(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib) nuclear@16: { nuclear@16: return (int)mesh->vertices.size(); nuclear@16: } nuclear@16: nuclear@16: int goat3d_get_mesh_face_count(struct goat3d_mesh *mesh) nuclear@16: { nuclear@16: return (int)mesh->faces.size(); nuclear@16: } nuclear@16: nuclear@19: // VECDATA is in goat3d_impl.h nuclear@16: void goat3d_set_mesh_attribs(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib, const void *data, int vnum) nuclear@16: { nuclear@16: if(attrib == GOAT3D_MESH_ATTR_VERTEX) { nuclear@16: mesh->vertices = VECDATA(Vector3, data, vnum); nuclear@16: return; nuclear@16: } nuclear@16: nuclear@16: if(vnum != (int)mesh->vertices.size()) { nuclear@16: logmsg(LOG_ERROR, "trying to set mesh attrib data with number of elements different than the vertex array\n"); nuclear@16: return; nuclear@16: } nuclear@16: nuclear@16: switch(attrib) { nuclear@16: case GOAT3D_MESH_ATTR_NORMAL: nuclear@16: mesh->normals = VECDATA(Vector3, data, vnum); nuclear@16: break; nuclear@16: case GOAT3D_MESH_ATTR_TANGENT: nuclear@16: mesh->tangents = VECDATA(Vector3, data, vnum); nuclear@16: break; nuclear@16: case GOAT3D_MESH_ATTR_TEXCOORD: nuclear@16: mesh->texcoords = VECDATA(Vector2, data, vnum); nuclear@16: break; nuclear@16: case GOAT3D_MESH_ATTR_SKIN_WEIGHT: nuclear@16: mesh->skin_weights = VECDATA(Vector4, data, vnum); nuclear@16: break; nuclear@16: case GOAT3D_MESH_ATTR_SKIN_MATRIX: nuclear@16: mesh->skin_matrices = VECDATA(Int4, data, vnum); nuclear@16: break; nuclear@16: case GOAT3D_MESH_ATTR_COLOR: nuclear@16: mesh->colors = VECDATA(Vector4, data, vnum); nuclear@16: default: nuclear@16: break; nuclear@16: } nuclear@16: } nuclear@16: nuclear@16: void *goat3d_get_mesh_attribs(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib) nuclear@16: { nuclear@16: return goat3d_get_mesh_attrib(mesh, attrib, 0); nuclear@16: } nuclear@16: nuclear@16: void *goat3d_get_mesh_attrib(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib, int idx) nuclear@16: { nuclear@16: switch(attrib) { nuclear@16: case GOAT3D_MESH_ATTR_VERTEX: nuclear@16: return mesh->vertices.empty() ? 0 : (void*)&mesh->vertices[idx]; nuclear@16: case GOAT3D_MESH_ATTR_NORMAL: nuclear@16: return mesh->normals.empty() ? 0 : (void*)&mesh->normals[idx]; nuclear@16: case GOAT3D_MESH_ATTR_TANGENT: nuclear@16: return mesh->tangents.empty() ? 0 : (void*)&mesh->tangents[idx]; nuclear@16: case GOAT3D_MESH_ATTR_TEXCOORD: nuclear@16: return mesh->texcoords.empty() ? 0 : (void*)&mesh->texcoords[idx]; nuclear@16: case GOAT3D_MESH_ATTR_SKIN_WEIGHT: nuclear@16: return mesh->skin_weights.empty() ? 0 : (void*)&mesh->skin_weights[idx]; nuclear@16: case GOAT3D_MESH_ATTR_SKIN_MATRIX: nuclear@16: return mesh->skin_matrices.empty() ? 0 : (void*)&mesh->skin_matrices[idx]; nuclear@16: case GOAT3D_MESH_ATTR_COLOR: nuclear@16: return mesh->colors.empty() ? 0 : (void*)&mesh->colors[idx]; nuclear@16: default: nuclear@16: break; nuclear@16: } nuclear@16: return 0; nuclear@16: } nuclear@16: nuclear@16: nuclear@16: void goat3d_set_mesh_faces(struct goat3d_mesh *mesh, const int *data, int num) nuclear@16: { nuclear@16: mesh->faces = VECDATA(Face, data, num); nuclear@16: } nuclear@16: nuclear@16: int *goat3d_get_mesh_faces(struct goat3d_mesh *mesh) nuclear@16: { nuclear@16: return goat3d_get_mesh_face(mesh, 0); nuclear@16: } nuclear@16: nuclear@16: int *goat3d_get_mesh_face(struct goat3d_mesh *mesh, int idx) nuclear@16: { nuclear@16: return mesh->faces.empty() ? 0 : mesh->faces[idx].v; nuclear@16: } nuclear@16: nuclear@16: // immedate mode state nuclear@16: static enum goat3d_im_primitive im_prim; nuclear@16: static struct goat3d_mesh *im_mesh; nuclear@16: static Vector3 im_norm, im_tang; nuclear@16: static Vector2 im_texcoord; nuclear@16: static Vector4 im_skinw, im_color = Vector4(1, 1, 1, 1); nuclear@16: static Int4 im_skinmat; nuclear@16: static bool im_use[NUM_GOAT3D_MESH_ATTRIBS]; nuclear@16: nuclear@16: nuclear@16: void goat3d_begin(struct goat3d_mesh *mesh, enum goat3d_im_primitive prim) nuclear@16: { nuclear@16: mesh->vertices.clear(); nuclear@16: mesh->normals.clear(); nuclear@16: mesh->tangents.clear(); nuclear@16: mesh->texcoords.clear(); nuclear@16: mesh->skin_weights.clear(); nuclear@16: mesh->skin_matrices.clear(); nuclear@16: mesh->colors.clear(); nuclear@16: mesh->faces.clear(); nuclear@16: nuclear@16: im_mesh = mesh; nuclear@16: memset(im_use, 0, sizeof im_use); nuclear@16: nuclear@16: im_prim = prim; nuclear@16: } nuclear@16: nuclear@16: void goat3d_end(void) nuclear@16: { nuclear@16: switch(im_prim) { nuclear@16: case GOAT3D_TRIANGLES: nuclear@17: { nuclear@17: int num_faces = (int)im_mesh->vertices.size() / 3; nuclear@17: im_mesh->faces.resize(num_faces); nuclear@17: nuclear@17: int vidx = 0; nuclear@17: for(int i=0; ifaces[i].v[0] = vidx++; nuclear@17: im_mesh->faces[i].v[1] = vidx++; nuclear@17: im_mesh->faces[i].v[2] = vidx++; nuclear@17: } nuclear@17: } nuclear@16: break; nuclear@16: nuclear@16: case GOAT3D_QUADS: nuclear@17: { nuclear@17: int num_quads = (int)im_mesh->vertices.size() / 4; nuclear@17: im_mesh->faces.resize(num_quads * 2); nuclear@17: nuclear@17: int vidx = 0; nuclear@17: for(int i=0; ifaces[i * 2].v[0] = vidx; nuclear@17: im_mesh->faces[i * 2].v[1] = vidx + 1; nuclear@17: im_mesh->faces[i * 2].v[2] = vidx + 2; nuclear@17: nuclear@17: im_mesh->faces[i * 2 + 1].v[0] = vidx; nuclear@17: im_mesh->faces[i * 2 + 1].v[1] = vidx + 2; nuclear@17: im_mesh->faces[i * 2 + 1].v[2] = vidx + 3; nuclear@17: nuclear@17: vidx += 4; nuclear@17: } nuclear@17: } nuclear@16: break; nuclear@16: nuclear@16: default: nuclear@16: return; nuclear@16: }; nuclear@16: } nuclear@16: nuclear@16: void goat3d_vertex3f(float x, float y, float z) nuclear@16: { nuclear@16: im_mesh->vertices.push_back(Vector3(x, y, z)); nuclear@16: if(im_use[GOAT3D_MESH_ATTR_NORMAL]) { nuclear@16: im_mesh->normals.push_back(im_norm); nuclear@16: } nuclear@16: if(im_use[GOAT3D_MESH_ATTR_TANGENT]) { nuclear@16: im_mesh->tangents.push_back(im_tang); nuclear@16: } nuclear@16: if(im_use[GOAT3D_MESH_ATTR_TEXCOORD]) { nuclear@16: im_mesh->texcoords.push_back(im_texcoord); nuclear@16: } nuclear@16: if(im_use[GOAT3D_MESH_ATTR_SKIN_WEIGHT]) { nuclear@16: im_mesh->skin_weights.push_back(im_skinw); nuclear@16: } nuclear@16: if(im_use[GOAT3D_MESH_ATTR_SKIN_MATRIX]) { nuclear@16: im_mesh->skin_matrices.push_back(im_skinmat); nuclear@16: } nuclear@16: if(im_use[GOAT3D_MESH_ATTR_COLOR]) { nuclear@16: im_mesh->colors.push_back(im_color); nuclear@16: } nuclear@16: } nuclear@16: nuclear@16: void goat3d_normal3f(float x, float y, float z) nuclear@16: { nuclear@16: im_norm = Vector3(x, y, z); nuclear@17: im_use[GOAT3D_MESH_ATTR_NORMAL] = true; nuclear@16: } nuclear@16: nuclear@16: void goat3d_tangent3f(float x, float y, float z) nuclear@16: { nuclear@16: im_tang = Vector3(x, y, z); nuclear@17: im_use[GOAT3D_MESH_ATTR_TANGENT] = true; nuclear@16: } nuclear@16: nuclear@16: void goat3d_texcoord2f(float x, float y) nuclear@16: { nuclear@16: im_texcoord = Vector2(x, y); nuclear@17: im_use[GOAT3D_MESH_ATTR_TEXCOORD] = true; nuclear@16: } nuclear@16: nuclear@16: void goat3d_skin_weight4f(float x, float y, float z, float w) nuclear@16: { nuclear@16: im_skinw = Vector4(x, y, z, w); nuclear@17: im_use[GOAT3D_MESH_ATTR_SKIN_WEIGHT] = true; nuclear@16: } nuclear@16: nuclear@16: void goat3d_skin_matrix4i(int x, int y, int z, int w) nuclear@16: { nuclear@16: im_skinmat.x = x; nuclear@16: im_skinmat.y = y; nuclear@16: im_skinmat.z = z; nuclear@16: im_skinmat.w = w; nuclear@17: im_use[GOAT3D_MESH_ATTR_SKIN_MATRIX] = true; nuclear@16: } nuclear@16: nuclear@16: void goat3d_color3f(float x, float y, float z) nuclear@16: { nuclear@17: goat3d_color4f(x, y, z, 1.0f); nuclear@16: } nuclear@16: nuclear@16: void goat3d_color4f(float x, float y, float z, float w) nuclear@16: { nuclear@16: im_color = Vector4(x, y, z, w); nuclear@17: im_use[GOAT3D_MESH_ATTR_COLOR] = true; nuclear@16: } nuclear@16: nuclear@16: void goat3d_add_mesh(struct goat3d *g, struct goat3d_mesh *mesh) nuclear@16: { nuclear@16: g->scn->add_mesh(mesh); nuclear@16: } nuclear@16: nuclear@19: int goat3d_get_mesh_count(struct goat3d *g) nuclear@19: { nuclear@19: return g->scn->get_mesh_count(); nuclear@19: } nuclear@19: nuclear@19: struct goat3d_mesh *goat3d_get_mesh(struct goat3d *g, int idx) nuclear@19: { nuclear@19: return (goat3d_mesh*)g->scn->get_mesh(idx); nuclear@19: } nuclear@19: nuclear@16: nuclear@16: } // extern "C" nuclear@16: nuclear@16: nuclear@16: static long read_file(void *buf, size_t bytes, void *uptr) nuclear@16: { nuclear@16: return (long)fread(buf, 1, bytes, (FILE*)uptr); nuclear@16: } nuclear@16: nuclear@16: static long write_file(const void *buf, size_t bytes, void *uptr) nuclear@16: { nuclear@16: return (long)fwrite(buf, 1, bytes, (FILE*)uptr); nuclear@16: } nuclear@16: nuclear@16: static long seek_file(long offs, int whence, void *uptr) nuclear@16: { nuclear@16: if(fseek((FILE*)uptr, offs, whence) == -1) { nuclear@16: return -1; nuclear@16: } nuclear@16: return ftell((FILE*)uptr); nuclear@16: }