Skip to content

Instantly share code, notes, and snippets.

@wernsey
Created December 30, 2017 12:07
Show Gist options
  • Save wernsey/0e9fc05aabbfdabf2b6dfffff21f27aa to your computer and use it in GitHub Desktop.
Save wernsey/0e9fc05aabbfdabf2b6dfffff21f27aa to your computer and use it in GitHub Desktop.
Milkshape 3D model loading in C
/*
http://paulbourke.net/dataformats/ms3d/ms3dspec.h
http://www.chumba.ch/chumbalum-soft/files/ms3dsdk184.zip
http://sappersblog.blogspot.co.za/2014/08/milkshape-3d-185-ms3d-file-format.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#pragma pack(push, 1)
typedef struct {
char id[10];
int version;
} ms3d_header;
typedef struct {
uint8_t flags;
float vertex[3];
int8_t boneId;
uint8_t refCnt;
} ms3d_vertex;
typedef struct {
uint16_t flags;
uint16_t verts[3];
float norms[3][3];
float s[3];
float t[3];
uint8_t smthGrp;
uint8_t grpIndex;
} ms3d_triangle;
typedef struct {
uint8_t flags;
char name[32];
uint16_t nTris;
uint16_t *triIdx;
int8_t matIdx;
} ms3d_group;
typedef struct {
char name[32];
float ambient[4];
float diffuse[4];
float specular[4];
float emissive[4];
float shininess;
float transparency;
char mode;
char texture[128];
char alphamap[128];
} ms3d_material;
typedef struct {
float time;
float rotation[3];
} ms3d_keyframe_rot;
typedef struct {
float time;
float position[3];
} ms3d_keyframe_pos;
typedef struct {
uint8_t flags;
char name[32];
char parentName[32];
float rotation[3];
float position[3];
uint16_t nKeyFramesRot;
uint16_t nKeyFramesPos;
ms3d_keyframe_rot *keyFramesRot;
ms3d_keyframe_pos *keyFramesPos;
} ms3d_joint;
typedef struct {
uint16_t nVerts;
uint16_t nTris;
uint16_t nGrps;
uint16_t nMats;
uint16_t nJoints;
float animFps;
float currTime;
int32_t totalFrames;
ms3d_vertex *verts;
ms3d_triangle *tris;
ms3d_group *grps;
ms3d_material *mats;
ms3d_joint *joints;
} ms3d_model;
#pragma pack(pop)
void ms3d_free(ms3d_model *mdl);
ms3d_model *ms3d_load(const char *filename) {
ms3d_header hdr;
ms3d_model *mdl;
int i;
FILE *f = fopen(filename,"rb");
if(!f) return NULL;
if(fread(&hdr, sizeof hdr, 1, f) != 1
|| memcmp(hdr.id, "MS3D000000", 10)) {
fclose(f);
fprintf(stderr, "Not a MS3D file");
return NULL;
}
printf("Version %d\n", hdr.version);
mdl = malloc(sizeof *mdl);
memset(mdl, 0, sizeof *mdl);
if(fread(&mdl->nVerts, sizeof mdl->nVerts, 1, f) != 1)
goto error;
printf("Vertices: %d\n", mdl->nVerts);
mdl->verts = calloc(mdl->nVerts, sizeof *mdl->verts);
if(fread(mdl->verts, sizeof *mdl->verts, mdl->nVerts, f) != mdl->nVerts)
goto error;
if(fread(&mdl->nTris, sizeof mdl->nTris, 1, f) != 1)
goto error;
printf("Triangles: %d\n", mdl->nTris);
mdl->tris = calloc(mdl->nTris, sizeof *mdl->tris);
if(fread(mdl->tris, sizeof *mdl->tris, mdl->nTris, f) != mdl->nTris)
goto error;
if(fread(&mdl->nGrps, sizeof mdl->nGrps, 1, f) != 1)
goto error;
printf("Groups: %d\n", mdl->nGrps);
mdl->grps = calloc(mdl->nGrps, sizeof *mdl->grps);
for(i = 0; i < mdl->nGrps; i++) {
ms3d_group *g = &mdl->grps[i];
if(fread(&g->flags, sizeof g->flags, 1, f) != 1 ||
fread(&g->name, sizeof g->name, 1, f) != 1 ||
fread(&g->nTris, sizeof g->nTris, 1, f) != 1)
goto error;
printf("Group %d: '%s' : %d triangles\n", i, g->name, g->nTris);
g->triIdx = calloc(g->nTris, sizeof *g->triIdx);
if(fread(g->triIdx, sizeof *g->triIdx, g->nTris, f) != g->nTris)
goto error;
if(fread(&g->matIdx, sizeof g->matIdx, 1, f) != 1)
goto error;
}
if(fread(&mdl->nMats, sizeof mdl->nMats, 1, f) != 1)
goto error;
printf("Materials: %d\n", mdl->nMats);
mdl->mats = calloc(mdl->nMats, sizeof *mdl->mats);
if(fread(mdl->mats, sizeof *mdl->mats, mdl->nMats, f) != mdl->nMats)
goto error;
for(i = 0; i < mdl->nMats; i++) {
ms3d_material *m = &mdl->mats[i];
printf("Material %d: '%s'; '%s'\n", i, m->name, m->texture);
}
if(fread(&mdl->animFps, sizeof mdl->animFps, 1, f) != 1 ||
fread(&mdl->currTime, sizeof mdl->currTime, 1, f) != 1 ||
fread(&mdl->totalFrames, sizeof mdl->totalFrames, 1, f) != 1)
goto error;
printf("animFps: %f\ncurrTime: %f\ntotalFrames: %d\n", mdl->animFps, mdl->currTime, mdl->totalFrames);
if(fread(&mdl->nJoints, sizeof mdl->nJoints, 1, f) != 1)
goto error;
printf("Joints: %d\n", mdl->nJoints);
mdl->joints = calloc(mdl->nJoints, sizeof *mdl->joints);
for(i = 0; i < mdl->nJoints; i++) {
ms3d_joint *j = &mdl->joints[i];
if(fread(j, (sizeof *j) - (sizeof j->keyFramesRot) - (sizeof j->keyFramesPos), 1, f) != 1)
goto error;
printf("Joint %d: '%s' (%s) [%d;%d]\n", i, j->name, j->parentName, j->nKeyFramesRot, j->nKeyFramesPos);
j->keyFramesRot = calloc(j->nKeyFramesRot, sizeof *j->keyFramesRot);
j->keyFramesPos = calloc(j->nKeyFramesPos, sizeof *j->keyFramesPos);
if(fread(j->keyFramesRot, sizeof *j->keyFramesRot, j->nKeyFramesRot, f) != j->nKeyFramesRot ||
fread(j->keyFramesPos, sizeof *j->keyFramesPos, j->nKeyFramesPos, f) != j->nKeyFramesPos)
goto error;
}
printf("success\n");
goto done;
error:
ms3d_free(mdl);
mdl = NULL;
done:
fclose(f);
return mdl;
}
void ms3d_free(ms3d_model *mdl) {
int i;
if(!mdl) return;
if(mdl->verts) free(mdl->verts);
if(mdl->tris) free(mdl->tris);
if(mdl->grps) {
for(i = 0; i < mdl->nGrps; i++) {
if(mdl->grps[i].triIdx) free(mdl->grps[i].triIdx);
}
free(mdl->grps);
}
if(mdl->mats) free(mdl->mats);
if(mdl->joints) {
for(i = 0; i < mdl->nJoints; i++) {
if(mdl->joints[i].keyFramesRot) free(mdl->joints[i].keyFramesRot);
if(mdl->joints[i].keyFramesPos) free(mdl->joints[i].keyFramesPos);
}
free(mdl->joints);
}
free(mdl);
}
int main(int argc, char *argv[]) {
ms3d_model *mdl = ms3d_load("Animatedlion.ms3d");
if(!mdl) {
fprintf(stderr, "error\n");
return 1;
}
ms3d_free(mdl);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment