module MD2;
//..............................................................................
function StreamReadString(Stream _ifs, int _l) {
int i=0;
String s_tmpname<=new String;
s_tmpname.alloc(_l);
int c;
do {
c=_ifs.i8;
s_tmpname[i]=c;
} while (++i<_l);
s_tmpname.fixLength();
return deref s_tmpname;
}
// -----------------------------------------------------------------------------
class CMD2_Triangle {
int vertexIndices [3];
int textureIndices[3];
}
// -----------------------------------------------------------------------------
class CMD2_Frame {
CMD2 md2;
float scaling[3];
float translation[3];
String name;
int indexed_vertices[];
float vertices[];
float frame_scl;
float face_normals[]; // md2.numTriangles
float point_normals[]; // numTriangles*3
/* void */ convertIndexedVertices();
/* */ scaleFrame(float _scl);
/* */ calcNormals();
/* CGLMesh */ getGLMesh(Texture _tex);
/* */ createGLMesh(CGLMesh _mesh, Texture _tex);
}
//..............................................................................
CMD2_Frame::convertIndexedVertices() {
int ni=(indexed_vertices.numElements/4);
vertices.alloc(ni*3); vertices.numElements=vertices.maxElements;
int i=0;
int j=0;
float maxx=0,maxy=0,maxz=0,t;
compile loop(ni)
{
float x,y,z;
t=(indexed_vertices[i++]*scaling[0])+translation[0];
if(abs(t)>maxx)
maxx=abs(t);
vertices[j++]=t;
t=(indexed_vertices[i++]*scaling[1])+translation[1];
if(abs(t)>maxy)
maxy=abs(t);
vertices[j++]=t;
t=(indexed_vertices[i++]*scaling[2])+translation[2];
if(abs(t)>maxz)
maxz=abs(t);
vertices[j++]=t;
i++; // skip lightNormalIndex
}
// ---- normalize ----
maxx=(maxx==0)?1:(1/maxx);
maxy=(maxy==0)?1:(1/maxy);
maxz=(maxz==0)?1:(1/maxz);
frame_scl=(maxx<maxy)?(maxx<maxz)?maxx:maxz:(maxy<maxz)?maxy:maxz;
//trace "CMD2_Frame::convertIndexedVertices: converted "+indexed_vertices.numElements+" vertices.";
}
CMD2_Frame::scaleFrame {
int j=0;
float cx,cy,cz;
int ni=indexed_vertices.numElements/4;
compile loop(ni)
{
cx=vertices[j]; cy=vertices[j+1]; cz=vertices[j+2];
vertices[j ]=-cy*_scl;
vertices[j+1] =cz*_scl;
vertices[j+2]=-cx*_scl;
j=j+3;
}
}
CMD2_Frame::calcNormals() {
}
//..............................................................................
CMD2_Frame::getGLMesh {
CGLMesh m<=new CGLMesh;
createGLMesh(m, _tex);
return deref m;
}
CMD2_Frame::createGLMesh {
CGLMesh m<=_mesh;
m.tex<=_tex;
FloatArray m_vtx<=m.vertices;
FloatArray m_nrm<=m.normals;
FloatArray m_uv<=m.uvcoords;
IntArray m_col<=m.colors;
int i_totalNumVertices=md2.numTriangles*3;
m_vtx.alloc(i_totalNumVertices*3); m_vtx.numElements=m_vtx.maxElements;
m_nrm.alloc(i_totalNumVertices*3); m_nrm.numElements=m_nrm.maxElements;
m_uv.alloc(i_totalNumVertices*2); m_uv .numElements=m_uv .maxElements;
m_col.alloc(i_totalNumVertices); m_col.numElements=m_col.maxElements;
int i=0,j=0,k=0,l=0;
int ti;
CMD2_Triangle ctri;
compile loop(md2.numTriangles)
{
ctri<=md2.triangles[j++];
ti=ctri.vertexIndices[0]*3;
m_vtx[i++]=vertices[ti++];
m_vtx[i++]=vertices[ti++];
m_vtx[i++]=vertices[ti];
//trace "vtx=("+m_vtx[i-3]+"; "+m_vtx[i-2]+"; "+m_vtx[i-1]+")";
ti=ctri.textureIndices[0]*2;
m_uv[k++]=md2.texcoords[ti++];
m_uv[k++]=md2.texcoords[ti];
// trace "uv=("+m_uv[k-2]+"; "+m_uv[k-1]+")";
m_col[l++]=#ffffffff;
ti=ctri.vertexIndices[1]*3;
m_vtx[i++]=vertices[ti++];
m_vtx[i++]=vertices[ti++];
m_vtx[i++]=vertices[ti];
ti=ctri.textureIndices[1]*2;
m_uv[k++]=md2.texcoords[ti++];
m_uv[k++]=md2.texcoords[ti];
m_col[l++]=#ffffffff;
ti=ctri.vertexIndices[2]*3;
m_vtx[i++]=vertices[ti++];
m_vtx[i++]=vertices[ti++];
m_vtx[i++]=vertices[ti];
ti=ctri.textureIndices[2]*2;
m_uv[k++]=md2.texcoords[ti++];
m_uv[k++]=md2.texcoords[ti];
m_col[l++]=#ffffffff;
}
}
// -----------------------------------------------------------------------------
class CMD2 {
int version;
int skinWidth;
int skinHeight;
int frameSize;
int numSkins;
int numVertices;
int numTexCoords;
int numTriangles;
int numGLCommands;
int numFrames;
int offsetSkins;
int offsetTexCoords;
int offsetTriangles;
int offsetFrames;
int offsetGLCommands;
int offsetEnd;
CMD2_Triangle triangles[];
CMD2_Frame frames[];
float texcoords[]; /* u/v pairs, normalized */
/*bool*/ loadMD2(String _name);
/*bool*/ loadMD2FromStream(Stream _ifs);
/* */ parseTriangles(Stream _ifs);
/* */ parseFrames(Stream _ifs);
/* */ parseTexCoords(Stream _ifs);
/*CGLShapeAnim*/ getGLShapeAnim(Texture _tex);
}
//..............................................................................
CMD2::loadMD2 {
PakFile f;
if(f.open(_name))
{
f.byteOrder=LITTLE_ENDIAN;
int r=loadMD2FromStream(f);
f.close();
return r;
}
else
{
trace "[---] error opening MD2 filestream \""+_name+"\".";
return 0;
}
}
//..............................................................................
CMD2::loadMD2FromStream() {
trace "loadMD2FromStream()";
if(_ifs.i8=='I')
if(_ifs.i8=='D')
if(_ifs.i8=='P')
if(_ifs.i8/*=='2'*/)
{
trace "[...] found header";
version = _ifs.i32;
skinWidth = _ifs.i32;
skinHeight = _ifs.i32;
frameSize = _ifs.i32;
numSkins = _ifs.i32;
numVertices = _ifs.i32;
numTexCoords = _ifs.i32;
numTriangles = _ifs.i32;
numGLCommands = _ifs.i32;
numFrames = _ifs.i32;
offsetSkins = _ifs.i32;
offsetTexCoords = _ifs.i32;
offsetTriangles = _ifs.i32;
offsetFrames = _ifs.i32;
offsetGLCommands = _ifs.i32;
offsetEnd = _ifs.i32;
trace "\tversion ="+version;
trace "\tskinWidth ="+skinWidth;
trace "\tskinHeight ="+skinHeight;
trace "\tframeSize ="+frameSize;
trace "\tnumSkins ="+numSkins;
trace "\tnumVertices ="+numVertices;
trace "\tnumTriangles ="+numTriangles;
trace "\tnumGLCommands ="+numGLCommands;
trace "\tnumFrames ="+numFrames;
trace "\toffsetSkins ="+offsetSkins;
trace "\toffsetTexCoords ="+offsetTexCoords;
trace "\toffsetTriangles ="+offsetTriangles;
trace "\toffsetFrames ="+offsetFrames;
trace "\toffsetGLCommands="+offsetGLCommands;
trace "\toffsetEnd ="+offsetEnd;
parseTexCoords(_ifs);
parseTriangles(_ifs);
parseFrames(_ifs);
return 1;
}
return 0;
}
//..............................................................................
CMD2::parseTriangles {
_ifs.offset=offsetTriangles;
triangles.alloc(numTriangles);
CMD2_Triangle ctri;
loop(numTriangles)
{
ctri<=triangles.nextFree;
IntArray tex<=ctri.textureIndices;
IntArray vtx<=ctri.vertexIndices;
tex.numElements=3;
vtx.numElements=3;
vtx[0]=_ifs.i16;
vtx[1]=_ifs.i16;
vtx[2]=_ifs.i16;
tex[0]=_ifs.i16;
tex[1]=_ifs.i16;
tex[2]=_ifs.i16;
}
trace "[...] read "+numTriangles+" triangles.";
}
//..............................................................................
CMD2::parseFrames {
_ifs.offset=offsetFrames;
frames.alloc(numFrames);
CMD2_Frame cf;
int framenr=0;
float scl=1;
loop(numFrames)
{
cf<=frames.nextFree;
cf.md2<=this;
IntArray vtx<=cf.indexed_vertices;
vtx.alloc(numVertices*4); vtx.numElements=vtx.maxElements;
FloatArray fa<=cf.scaling;
fa[0]=_ifs.f32;
fa[1]=_ifs.f32;
fa[2]=_ifs.f32;
fa<=cf.translation;
fa[0]=_ifs.f32;
fa[1]=_ifs.f32;
fa[2]=_ifs.f32;
cf.name=StreamReadString(_ifs, 16);
trace "parseFrame["+framenr+++"] name=\""+cf.name+"\".";
int i=0;
compile loop(numVertices)
{
vtx[i++]=_ifs.i8;
vtx[i++]=_ifs.i8;
vtx[i++]=_ifs.i8;
vtx[i++]=_ifs.i8;
}
cf.convertIndexedVertices();
if(cf.frame_scl<scl)
scl=cf.frame_scl;
}
frames.numElements=0;
loop(numFrames)
{
cf<=frames.nextFree;
cf.scaleFrame(scl);
}
}
//..............................................................................
CMD2::parseTexCoords {
trace "parseTExCoords:";
if(numTexCoords&&skinWidth&&skinHeight)
{
texcoords.alloc(2*numTexCoords);
_ifs.offset=offsetTexCoords;
int i=0;
compile loop(numTexCoords)
{
texcoords[i++]=tcfloat(_ifs.i16)/skinWidth;
texcoords[i++]=tcfloat(_ifs.i16)/skinHeight;
trace "parse texcoord ("+texcoords[i-2]+"; "+texcoords[i-1]+")";
}
}
trace "[...] CMD2::parseTexCoords: parsed "+numTexCoords+" texture coordinates.";
}
//..............................................................................
CMD2::getGLShapeAnim {
CGLShapeAnim a<=new CGLShapeAnim;
a.meshes.alloc(numFrames);
int i=0;
compile loop(numFrames)
{
CGLMesh m<=a.meshes.nextFree;
CMD2_Frame f<=frames[i++];
f.createGLMesh(m, _tex);
}
a.initAnim(0, numFrames, 0, numFrames);
a.initVertices();
return deref a;
}