This should fix the problem. I do it a bit strange because the md2 format handles texcoords different then irrlicht. It uses indexed texcoord. Also, in the faerie.md2 some vertices apparently has the same pos and normal, but different texcoords. Anyway, due to this, the loader has to loop through all existing vertices, each time a new one is created, to see if it already exists (with the same texcoords). This, unfortunately increases the loading time. If anybody know a faster way, please let my know.
Here is the new loadfile:
Code: Select all
#define S3DVERTEX_CLOSE_ENOUGH(v1, v2, e) ((v1.Pos.X <= v2.Pos.X + e && v1.Pos.X >= v2.Pos.X - e) && \
(v1.Pos.Y <= v2.Pos.Y + e && v1.Pos.Y >= v2.Pos.Y - e) && \
(v1.Pos.Z <= v2.Pos.Z + e && v1.Pos.Z >= v2.Pos.Z - e) && \
(v1.TCoords.X <= v2.TCoords.X + e && v1.TCoords.X >= v2.TCoords.X - e) && \
(v1.TCoords.Y <= v2.TCoords.Y + e && v1.TCoords.Y >= v2.TCoords.Y - e))
//! loads an md3 file
bool CAnimatedMeshMD2::loadFile(io::IReadFile* file)
{
if (!file)
return false;
SMD2Header header;
s8* frames = 0;
file->read(&header, sizeof(SMD2Header));
if (header.magic != MD2_MAGIC_NUMBER || header.version != MD2_VERSION)
{
os::Printer::log("MD2 Loader: Wrong file header", file->getFileName(), ELL_WARNING);
return false;
}
// create Memory for indices and frames
Indices.reallocate(header.numTriangles);
FrameList = new core::array<video::S3DVertex>[header.numFrames];
FrameCount = header.numFrames;
s32 i;
for (i=0; i<header.numFrames; ++i)
FrameList[i].reallocate(header.numVertices);
// read TextureCoords
file->seek(header.offsetTexcoords, false);
SMD2TextureCoordinate* textureCoords = new SMD2TextureCoordinate[header.numTexcoords];
if (!file->read(textureCoords, sizeof(SMD2TextureCoordinate)*header.numTexcoords))
{
os::Printer::log("MD2 Loader: Error reading TextureCoords.", file->getFileName(), ELL_ERROR);
return false;
}
// read Triangles
file->seek(header.offsetTriangles, false);
SMD2Triangle *triangles = new SMD2Triangle[header.numTriangles];
if (!file->read(triangles, header.numTriangles *sizeof(SMD2Triangle)))
{
os::Printer::log("MD2 Loader: Error reading triangles.", file->getFileName(), ELL_ERROR);
return false;
}
// read Vertices
s8 buffer[MD2_MAX_VERTS*4+128];
SMD2Frame* frame = (SMD2Frame*)buffer;
core::array< core::vector3df >* vertices = new core::array< core::vector3df >[header.numFrames];
core::array< core::vector3df >* normals = new core::array< core::vector3df >[header.numFrames];
file->seek(header.offsetFrames, false);
for (i = 0; i<header.numFrames; ++i)
{
// read vertices
vertices[i].reallocate(header.numVertices);
file->read(frame, header.frameSize);
// store frame data
SFrameData fdata;
fdata.begin = i;
fdata.end = i;
fdata.fps = 7;
if (frame->name[0])
{
for (s32 s = 0; frame->name[s]!=0 && (frame->name[s] < '0' ||
frame->name[s] > '9'); ++s)
fdata.name += frame->name[s];
if (!FrameData.empty() && FrameData[FrameData.size()-1].name == fdata.name)
++FrameData[FrameData.size()-1].end;
else
FrameData.push_back(fdata);
}
// add vertices
for (s32 j=0; j<header.numVertices; ++j)
{
core::vector3df v;
v.X = (f32)frame->vertices[j].vertex[0] * frame->scale[0] + frame->translate[0];
v.Z = (f32)frame->vertices[j].vertex[1] * frame->scale[1] + frame->translate[1]; // µ! z?
v.Y = (f32)frame->vertices[j].vertex[2] * frame->scale[2] + frame->translate[2];
vertices[i].push_back(v);
s32 normalidx = frame->vertices[j].lightNormalIndex;
if (normalidx > 0 && normalidx < Q2_VERTEX_NORMAL_TABLE_SIZE)
{
v.X = Q2_VERTEX_NORMAL_TABLE[normalidx][0];
v.Y = Q2_VERTEX_NORMAL_TABLE[normalidx][1];
v.Z = Q2_VERTEX_NORMAL_TABLE[normalidx][2];
}
normals[i].push_back(v);
}
// calculate bounding boxes
if (header.numVertices)
{
core::aabbox3d<f32> box;
box.reset(vertices[i][0]);
for (s32 j=1; j<header.numVertices; ++j)
box.addInternalPoint(vertices[i][j]);
BoxList.push_back(box);
}
}
// put triangles into frame list
f32 dmaxs = 1.0f/(header.skinWidth);
f32 dmaxt = 1.0f/(header.skinHeight);
video::S3DVertex vtx;
vtx.Color = video::SColor(255,255,255,255);
for (s32 f = 0; f<header.numFrames; ++f)
{
core::array< core::vector3df >& vert = vertices[f];
int currentIndex = 0;
for (s32 t=0; t<header.numTriangles; ++t)
{
for (s32 n=0; n<3; ++n)
{
vtx.Pos = vert[triangles[t].vertexIndices[n]];
vtx.TCoords.X = (textureCoords[triangles[t].textureIndices[n]].s + 0.5f) * dmaxs;
vtx.TCoords.Y = (textureCoords[triangles[t].textureIndices[n]].t + 0.5f) * dmaxt;
vtx.Normal = normals[f].pointer()[triangles[t].vertexIndices[n]];
int prev = -1;
for (u32 j = 0; j < FrameList[f].size(); j++) // See if this vertex already has been used.
{
if (S3DVERTEX_CLOSE_ENOUGH(vtx, FrameList[f][j], 0.00001f))
{
prev = j;
break;
}
}
if (prev < 0) FrameList[f].push_back(vtx);
if (f == 0)
{
if (prev < 0) Indices.push_back(currentIndex++);
else
Indices.push_back(prev);
}
}
}
}
//calculateNormals();
// reallocate interpolate buffer
if (header.numFrames)
{
InterpolateBuffer.set_used(FrameList[0].size());
s32 count = FrameList[0].size();
for (i=0; i<count; ++i)
{
InterpolateBuffer[i].TCoords = FrameList[0].pointer()[i].TCoords;
InterpolateBuffer[i].Color = vtx.Color;
}
}
// clean up
delete [] normals;
delete [] vertices;
delete [] triangles;
delete [] textureCoords;
TriangleCount = Indices.size() / 3;
// return
calculateBoundingBox();
return true;
}
BTW, shouldn't z and y be swapped in the line I've commented with a µ?
Best Regards,
Per Rasmussen.