#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_OCT_LOADER_
#include "COCTLoader.h"
#include "IVideoDriver.h"
#include "IFileSystem.h"
#include "os.h"
#include "SAnimatedMesh.h"
#include "SMeshBufferLightMap.h"
#include "irrString.h"
#include "CImage.h"
#include "ISceneManager.h"
namespace irr
{
namespace scene
{
COCTLoader::COCTLoader(ISceneManager* smgr, io::IFileSystem* fs)
: SceneManager(smgr), FileSystem(fs)
{
#ifdef _DEBUG
setDebugName("COCTLoader");
#endif
if (FileSystem)
FileSystem->grab();
}
COCTLoader::~COCTLoader()
{
if (FileSystem)
FileSystem->drop();
}
void COCTLoader::OCTLoadLights(io::IReadFile* file, scene::ISceneNode * parent, f32 radius, f32 intensityScale, bool rewind)
{
if (rewind)
file->seek(0);
octHeader header;
file->read(&header, sizeof(octHeader));
file->seek(sizeof(octVert)*header.numVerts, true);
file->seek(sizeof(octFace)*header.numFaces, true);
file->seek(sizeof(octTexture)*header.numTextures, true);
file->seek(sizeof(octLightmap)*header.numLightmaps, true);
octLight * lights = new octLight[header.numLights];
file->read(lights, header.numLights * sizeof(octLight));
for (u32 i = 0; i < header.numLights; i++)
{
const f32 intensity = lights[i].intensity * intensityScale;
SceneManager->addLightSceneNode(parent, core::vector3df(lights[i].pos[0], lights[i].pos[2], lights[i].pos[1]),
video::SColorf(lights[i].color[0] * intensity, lights[i].color[1] * intensity, lights[i].color[2] * intensity, 1.0f),
radius);
}
}
IAnimatedMesh* COCTLoader::createMesh(io::IReadFile* file)
{
if (!file)
return 0;
octHeader header;
file->read(&header, sizeof(octHeader));
octVert * verts = new octVert[header.numVerts];
octFace * faces = new octFace[header.numFaces];
octTexture * textures = new octTexture[header.numTextures];
octLightmap * lightmaps = new octLightmap[header.numLightmaps];
octLight * lights = new octLight[header.numLights];
file->read(verts, sizeof(octVert) * header.numVerts);
file->read(faces, sizeof(octFace) * header.numFaces);
u32 i;
for (i = 0; i < header.numTextures; i++) {
octTexture t;
file->read(&t, sizeof(octTexture));
textures[t.id] = t;
}
for (i = 0; i < header.numLightmaps; i++) {
octLightmap t;
file->read(&t, sizeof(octLightmap));
lightmaps[t.id] = t;
}
file->read(lights, sizeof(octLight) * header.numLights);
SMesh * Mesh = new SMesh();
for (i=0; i<(header.numTextures+1) * (header.numLightmaps+1); ++i)
{
scene::SMeshBufferLightMap* buffer = new scene::SMeshBufferLightMap();
buffer->Material.MaterialType = video::EMT_LIGHTMAP;
buffer->Material.Lighting = false;
Mesh->addMeshBuffer(buffer);
buffer->drop();
}
for (i = 0; i < header.numFaces; i++)
{
if (faces[i].numVerts < 3)
continue;
const f32* const a = verts[faces[i].firstVert].pos;
const f32* const b = verts[faces[i].firstVert+1].pos;
const f32* const c = verts[faces[i].firstVert+2].pos;
const core::vector3df normal =
core::plane3df(core::vector3df(a[0],a[1],a[2]), core::vector3df(b[0],c[1],c[2]), core::vector3df(c[0],c[1],c[2])).Normal;
const u32 textureID = core::min_(s32(faces[i].textureID), s32(header.numTextures - 1)) + 1;
const u32 lightmapID = core::min_(s32(faces[i].lightmapID),s32(header.numLightmaps - 1)) + 1;
SMeshBufferLightMap * meshBuffer = (SMeshBufferLightMap*)Mesh->getMeshBuffer(lightmapID * (header.numTextures + 1) + textureID);
const u32 base = meshBuffer->Vertices.size();
u32 v;
for (v = 0; v < faces[i].numVerts; ++v)
{
octVert * vv = &verts[faces[i].firstVert + v];
video::S3DVertex2TCoords vert;
vert.Pos.set(vv->pos[0], vv->pos[1], vv->pos[2]);
vert.Color = video::SColor(0,255,255,255);
vert.Normal.set(normal);
if (textureID == 0)
{
vert.TCoords.set(vv->lc[0], vv->lc[1]);
}
else
{
vert.TCoords.set(vv->tc[0], vv->tc[1]);
vert.TCoords2.set(vv->lc[0], vv->lc[1]);
}
meshBuffer->Vertices.push_back(vert);
}
u32 h = faces[i].numVerts - 1;
u32 l = 0;
for (v = 0; v < faces[i].numVerts - 2; ++v)
{
const u32 center = (v & 1)? h - 1: l + 1;
meshBuffer->Indices.push_back(base + h);
meshBuffer->Indices.push_back(base + l);
meshBuffer->Indices.push_back(base + center);
if (v & 1)
--h;
else
++l;
}
}
core::array<video::ITexture*> tex;
tex.reallocate(header.numTextures + 1);
tex.push_back(0);
const core::stringc relpath = FileSystem->getFileDir(file->getFileName())+"/";
for (i = 1; i < (header.numTextures + 1); i++)
{
core::stringc path(textures[i-1].fileName);
path.replace('\\','/');
if (FileSystem->existFile(path))
tex.push_back(SceneManager->getVideoDriver()->getTexture(path));
else
tex.push_back(SceneManager->getVideoDriver()->getTexture( (relpath + path) ));
}
core::array<video::ITexture*> lig;
lig.set_used(header.numLightmaps + 1);
lig[0] = 0;
const u32 lightmapWidth = 128;
const u32 lightmapHeight = 128;
const core::dimension2d<u32> lmapsize(lightmapWidth, lightmapHeight);
bool oldMipMapState = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
video::CImage tmpImage(video::ECF_R8G8B8, lmapsize);
for (i = 1; i < (header.numLightmaps + 1); ++i)
{
core::stringc lightmapname = file->getFileName();
lightmapname += ".lightmap.";
lightmapname += (int)i;
const octLightmap* lm = &lightmaps[i-1];
for (u32 x=0; x<lightmapWidth; ++x)
{
for (u32 y=0; y<lightmapHeight; ++y)
{
tmpImage.setPixel(x, y,
video::SColor(255,
lm->data[x][y][2],
lm->data[x][y][1],
lm->data[x][y][0]));
}
}
lig[i] = SceneManager->getVideoDriver()->addTexture(lightmapname.c_str(), &tmpImage);
}
SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState);
delete [] verts;
delete [] faces;
delete [] textures;
delete [] lightmaps;
delete [] lights;
for (i = 0; i < header.numLightmaps + 1; i++)
{
for (u32 j = 0; j < header.numTextures + 1; j++)
{
u32 mb = i * (header.numTextures + 1) + j;
SMeshBufferLightMap * meshBuffer = (SMeshBufferLightMap*)Mesh->getMeshBuffer(mb);
meshBuffer->Material.setTexture(0, tex[j]);
meshBuffer->Material.setTexture(1, lig[i]);
if (meshBuffer->Material.getTexture(0) == 0)
{
meshBuffer->Material.setTexture(0, meshBuffer->Material.getTexture(1));
meshBuffer->Material.setTexture(1, 0);
}
if (meshBuffer->Material.getTexture(1) == 0)
{
meshBuffer->Material.MaterialType = video::EMT_SOLID;
meshBuffer->Material.Lighting = true;
}
}
}
i = 0;
while(i < Mesh->MeshBuffers.size())
{
if (Mesh->MeshBuffers[i]->getVertexCount() == 0 ||
Mesh->MeshBuffers[i]->getIndexCount() == 0 ||
Mesh->MeshBuffers[i]->getMaterial().getTexture(0) == 0)
{
Mesh->MeshBuffers[i]->drop();
Mesh->MeshBuffers.erase(i);
}
else
{
++i;
}
}
for (i = 0; i < Mesh->MeshBuffers.size(); ++i)
{
Mesh->MeshBuffers[i]->recalculateBoundingBox();
}
Mesh->recalculateBoundingBox();
SAnimatedMesh* AMesh = new SAnimatedMesh();
AMesh->Type = EAMT_OCT;
AMesh->addMesh(Mesh);
AMesh->recalculateBoundingBox();
Mesh->drop();
return AMesh;
}
bool COCTLoader::isALoadableFileExtension(const io::path& filename) const
{
return core::hasFileExtension ( filename, "oct" );
}
}
}
#endif