goat3d
diff converters/ass2goat/src/main.c @ 64:99715321ad6d
merged
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 17 Apr 2014 08:53:42 +0300 |
parents | ca549434dc95 |
children |
line diff
1.1 --- a/converters/ass2goat/src/main.c Thu Apr 17 08:50:36 2014 +0300 1.2 +++ b/converters/ass2goat/src/main.c Thu Apr 17 08:53:42 2014 +0300 1.3 @@ -5,28 +5,52 @@ 1.4 #include "assimp/postprocess.h" 1.5 #include "assimp/scene.h" 1.6 1.7 -int convert(const char *infname, const char *outfname); 1.8 +enum { 1.9 + CONV_SCENE, 1.10 + CONV_ANIM 1.11 +}; 1.12 + 1.13 +int convert(const char *infname); 1.14 +int convert_anim(const char *infname); 1.15 void process_material(struct goat3d_material *mtl, struct aiMaterial *aimtl); 1.16 +void process_mesh(struct goat3d *goat, struct goat3d_mesh *mesh, struct aiMesh *aimesh); 1.17 void process_node(struct goat3d *goat, struct goat3d_node *parent, struct aiNode *ainode); 1.18 +int process_anim(struct goat3d *goat, struct aiAnimation *aianim); 1.19 +static int output_filename(char *buf, int bufsz, const char *fname, const char *suffix); 1.20 +static long assimp_time(const struct aiAnimation *anim, double aitime); 1.21 1.22 int main(int argc, char **argv) 1.23 { 1.24 int i, num_done = 0; 1.25 + int conv_targ = CONV_SCENE; 1.26 1.27 for(i=1; i<argc; i++) { 1.28 if(argv[i][0] == '-') { 1.29 + if(argv[i][2] != 0) { 1.30 + fprintf(stderr, "invalid option: %s\n", argv[i]); 1.31 + return 1; 1.32 + } 1.33 + 1.34 + switch(argv[i][1]) { 1.35 + case 'a': 1.36 + conv_targ = CONV_ANIM; 1.37 + break; 1.38 + 1.39 + case 's': 1.40 + conv_targ = CONV_SCENE; 1.41 + break; 1.42 + 1.43 + default: 1.44 + fprintf(stderr, "invalid option: %s\n", argv[i]); 1.45 + return 1; 1.46 + } 1.47 + 1.48 } else { 1.49 - char *lastdot; 1.50 - char *outfname = malloc(strlen(argv[i]) + 4); 1.51 - strcpy(outfname, argv[i]); 1.52 - 1.53 - if((lastdot = strrchr(outfname, '.'))) { 1.54 - *lastdot = 0; 1.55 + if(conv_targ == CONV_SCENE) { 1.56 + convert(argv[i]); 1.57 + } else { 1.58 + convert_anim(argv[i]); 1.59 } 1.60 - strcat(outfname, ".xml"); 1.61 - 1.62 - printf("converting %s -> %s\n", argv[i], outfname); 1.63 - convert(argv[i], outfname); 1.64 num_done++; 1.65 } 1.66 } 1.67 @@ -39,7 +63,7 @@ 1.68 return 0; 1.69 } 1.70 1.71 -#define PPFLAGS \ 1.72 +#define SCE_PPFLAGS \ 1.73 (aiProcess_Triangulate | \ 1.74 aiProcess_GenNormals | \ 1.75 aiProcess_JoinIdenticalVertices | \ 1.76 @@ -47,13 +71,23 @@ 1.77 aiProcess_LimitBoneWeights | \ 1.78 aiProcess_GenUVCoords) 1.79 1.80 -int convert(const char *infname, const char *outfname) 1.81 +#define ANM_PPFLAGS \ 1.82 + (aiProcess_LimitBoneWeights) 1.83 + 1.84 +int convert(const char *infname) 1.85 { 1.86 - int i; 1.87 + int i, bufsz; 1.88 const struct aiScene *aiscn; 1.89 struct goat3d *goat; 1.90 + char *outfname; 1.91 1.92 - if(!(aiscn = aiImportFile(infname, PPFLAGS))) { 1.93 + bufsz = output_filename(0, 0, infname, "goat3d"); 1.94 + outfname = alloca(bufsz); 1.95 + output_filename(outfname, bufsz, infname, "goat3d"); 1.96 + printf("converting %s -> %s\n", infname, outfname); 1.97 + 1.98 + 1.99 + if(!(aiscn = aiImportFile(infname, SCE_PPFLAGS))) { 1.100 fprintf(stderr, "failed to import %s\n", infname); 1.101 return -1; 1.102 } 1.103 @@ -68,6 +102,14 @@ 1.104 goat3d_add_mtl(goat, mat); 1.105 } 1.106 1.107 + for(i=0; i<(int)aiscn->mNumMeshes; i++) { 1.108 + struct aiMesh *aimesh = aiscn->mMeshes[i]; 1.109 + struct goat3d_mesh *mesh = goat3d_create_mesh(); 1.110 + 1.111 + process_mesh(goat, mesh, aimesh); 1.112 + goat3d_add_mesh(goat, mesh); 1.113 + } 1.114 + 1.115 for(i=0; i<(int)aiscn->mRootNode->mNumChildren; i++) { 1.116 process_node(goat, 0, aiscn->mRootNode->mChildren[i]); 1.117 } 1.118 @@ -78,6 +120,42 @@ 1.119 return 0; 1.120 } 1.121 1.122 +int convert_anim(const char *infname) 1.123 +{ 1.124 + int i, bufsz; 1.125 + const struct aiScene *aiscn; 1.126 + struct goat3d *goat; 1.127 + char *outfname; 1.128 + 1.129 + bufsz = output_filename(0, 0, infname, "goatanim"); 1.130 + outfname = alloca(bufsz); 1.131 + output_filename(outfname, bufsz, infname, "goatanim"); 1.132 + printf("converting %s -> %s\n", infname, outfname); 1.133 + 1.134 + 1.135 + if(!(aiscn = aiImportFile(infname, ANM_PPFLAGS))) { 1.136 + fprintf(stderr, "failed to import %s\n", infname); 1.137 + return -1; 1.138 + } 1.139 + 1.140 + goat = goat3d_create(); 1.141 + 1.142 + for(i=0; i<(int)aiscn->mRootNode->mNumChildren; i++) { 1.143 + process_node(goat, 0, aiscn->mRootNode->mChildren[i]); 1.144 + } 1.145 + 1.146 + for(i=0; i<aiscn->mNumAnimations; i++) { 1.147 + if(process_anim(goat, aiscn->mAnimations[i]) == -1) { 1.148 + return -1; 1.149 + } 1.150 + } 1.151 + 1.152 + goat3d_save_anim(goat, outfname); 1.153 + goat3d_free(goat); 1.154 + aiReleaseImport(aiscn); 1.155 + return 0; 1.156 +} 1.157 + 1.158 void process_material(struct goat3d_material *mtl, struct aiMaterial *aimtl) 1.159 { 1.160 struct aiString aistr; 1.161 @@ -126,11 +204,60 @@ 1.162 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_REFLECTION, aistr.data); 1.163 } 1.164 if(aiGetMaterialString(aimtl, AI_MATKEY_TEXTURE_OPACITY(0), &aistr) == aiReturn_SUCCESS) { 1.165 - // TODO this is semantically inverted... maybe add an alpha attribute? 1.166 + /* TODO this is semantically inverted... maybe add an alpha attribute? */ 1.167 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_TRANSMISSION, aistr.data); 1.168 } 1.169 } 1.170 1.171 +void process_mesh(struct goat3d *goat, struct goat3d_mesh *mesh, struct aiMesh *aimesh) 1.172 +{ 1.173 + int i, num_verts, num_faces; 1.174 + struct goat3d_material *mtl; 1.175 + 1.176 + if(aimesh->mName.length > 0) { 1.177 + goat3d_set_mesh_name(mesh, aimesh->mName.data); 1.178 + } 1.179 + 1.180 + if((mtl = goat3d_get_mtl(goat, aimesh->mMaterialIndex))) { 1.181 + goat3d_set_mesh_mtl(mesh, mtl); 1.182 + } 1.183 + 1.184 + num_verts = aimesh->mNumVertices; 1.185 + num_faces = aimesh->mNumFaces; 1.186 + 1.187 + for(i=0; i<num_verts; i++) { 1.188 + struct aiVector3D *v; 1.189 + struct aiColor4D *col; 1.190 + 1.191 + v = aimesh->mVertices + i; 1.192 + goat3d_add_mesh_attrib3f(mesh, GOAT3D_MESH_ATTR_VERTEX, v->x, v->y, v->z); 1.193 + 1.194 + if(aimesh->mNormals) { 1.195 + v = aimesh->mNormals + i; 1.196 + goat3d_add_mesh_attrib3f(mesh, GOAT3D_MESH_ATTR_NORMAL, v->x, v->y, v->z); 1.197 + } 1.198 + if(aimesh->mTangents) { 1.199 + v = aimesh->mTangents + i; 1.200 + goat3d_add_mesh_attrib3f(mesh, GOAT3D_MESH_ATTR_TANGENT, v->x, v->y, v->z); 1.201 + } 1.202 + if(aimesh->mTextureCoords[0]) { 1.203 + v = aimesh->mTextureCoords[0] + i; 1.204 + goat3d_add_mesh_attrib2f(mesh, GOAT3D_MESH_ATTR_TEXCOORD, v->x, v->y); 1.205 + } 1.206 + if(aimesh->mColors[0]) { 1.207 + col = aimesh->mColors[0] + i; 1.208 + goat3d_add_mesh_attrib4f(mesh, GOAT3D_MESH_ATTR_COLOR, col->r, col->g, col->b, col->a); 1.209 + } 1.210 + /* TODO: add bones */ 1.211 + } 1.212 + 1.213 + for(i=0; i<num_faces; i++) { 1.214 + struct aiFace *face = aimesh->mFaces + i; 1.215 + 1.216 + goat3d_add_mesh_face(mesh, face->mIndices[0], face->mIndices[1], face->mIndices[2]); 1.217 + } 1.218 +} 1.219 + 1.220 void process_node(struct goat3d *goat, struct goat3d_node *parent, struct aiNode *ainode) 1.221 { 1.222 int i; 1.223 @@ -145,3 +272,108 @@ 1.224 1.225 goat3d_add_node(goat, node); 1.226 } 1.227 + 1.228 +int process_anim(struct goat3d *goat, struct aiAnimation *aianim) 1.229 +{ 1.230 + int i, j, num_nodes, rnodes_count; 1.231 + const char *anim_name; 1.232 + 1.233 + if(aianim->mName.length <= 0) { 1.234 + anim_name = "unnamed"; 1.235 + } else { 1.236 + anim_name = aianim->mName.data; 1.237 + } 1.238 + 1.239 + num_nodes = goat3d_get_node_count(goat); 1.240 + 1.241 + rnodes_count = 0; 1.242 + for(i=0; i<num_nodes; i++) { 1.243 + int anim_idx; 1.244 + struct goat3d_node *n = goat3d_get_node(goat, i); 1.245 + /* skip non-root nodes */ 1.246 + if(goat3d_get_node_parent(n)) { 1.247 + break; 1.248 + } 1.249 + 1.250 + /* then add another animation to those root nodes */ 1.251 + anim_idx = goat3d_get_anim_count(n); 1.252 + goat3d_add_anim(n); 1.253 + goat3d_use_anim(n, anim_idx); 1.254 + 1.255 + goat3d_set_anim_name(n, anim_name); 1.256 + } 1.257 + 1.258 + /* for each animation "channel" ... */ 1.259 + for(i=0; i<(int)aianim->mNumChannels; i++) { 1.260 + struct goat3d_node *node; 1.261 + struct aiNodeAnim *ainodeanim = aianim->mChannels[i]; 1.262 + 1.263 + /* find the node it refers to */ 1.264 + const char *nodename = ainodeanim->mNodeName.data; 1.265 + if(!(node = goat3d_get_node_by_name(goat, nodename))) { 1.266 + fprintf(stderr, "failed to process animation for unknown node: %s\n", nodename); 1.267 + return -1; 1.268 + } 1.269 + 1.270 + /* add all the keys ... */ 1.271 + for(j=0; j<(int)ainodeanim->mNumPositionKeys; j++) { 1.272 + struct aiVectorKey *key = ainodeanim->mPositionKeys + j; 1.273 + long tm = assimp_time(aianim, key->mTime); 1.274 + goat3d_set_node_position(node, key->mValue.x, key->mValue.y, key->mValue.z, tm); 1.275 + } 1.276 + 1.277 + for(j=0; j<(int)ainodeanim->mNumRotationKeys; j++) { 1.278 + struct aiQuatKey *key = ainodeanim->mRotationKeys + j; 1.279 + long tm = assimp_time(aianim, key->mTime); 1.280 + goat3d_set_node_rotation(node, key->mValue.x, key->mValue.y, key->mValue.z, key->mValue.w, tm); 1.281 + } 1.282 + 1.283 + for(j=0; j<(int)ainodeanim->mNumScalingKeys; j++) { 1.284 + struct aiVectorKey *key = ainodeanim->mScalingKeys + j; 1.285 + long tm = assimp_time(aianim, key->mTime); 1.286 + goat3d_set_node_scaling(node, key->mValue.x, key->mValue.y, key->mValue.z, tm); 1.287 + } 1.288 + } 1.289 + 1.290 + return 0; 1.291 +} 1.292 + 1.293 +static int output_filename(char *buf, int bufsz, const char *fname, const char *suffix) 1.294 +{ 1.295 + int reqsz, namesz; 1.296 + char *tmpfname; 1.297 + const char *fname_end, *lastdot; 1.298 + 1.299 + lastdot = strrchr(fname, '.'); 1.300 + 1.301 + fname_end = lastdot ? lastdot : fname + strlen(fname); 1.302 + namesz = fname_end - fname; 1.303 + reqsz = namesz + strlen(suffix) + 2; /* plus 1 for the dot */ 1.304 + 1.305 + if(buf && bufsz) { 1.306 + tmpfname = alloca(namesz + 1); 1.307 + memcpy(tmpfname, fname, namesz); 1.308 + tmpfname[namesz] = 0; 1.309 + 1.310 + if(suffix) { 1.311 + snprintf(buf, bufsz, "%s.%s", tmpfname, suffix); 1.312 + } else { 1.313 + strncpy(buf, tmpfname, bufsz); 1.314 + } 1.315 + buf[bufsz - 1] = 0; 1.316 + } 1.317 + 1.318 + return reqsz; 1.319 +} 1.320 + 1.321 +static long assimp_time(const struct aiAnimation *anim, double aitime) 1.322 +{ 1.323 + double sec; 1.324 + if(anim->mTicksPerSecond < 1e-6) { 1.325 + /* assume time in frames? */ 1.326 + sec = aitime / 30.0; 1.327 + } else { 1.328 + sec = aitime / anim->mTicksPerSecond; 1.329 + } 1.330 + return (long)(sec * 1000.0); 1.331 +}