void VoxelSceneNode::preRenderMeshChunks()
{
    irr::core::vector3d<int> overDraw(1,0,1);

    irr::core::aabbox3df bounding = IRR.camera->getViewFrustum()->getBoundingBox();

    irr::core::vector3d<int> newAabboxStart(
        (int)floor(bounding.MinEdge.X / dimensions.X) - overDraw.X,
        (int)floor(bounding.MinEdge.Y / dimensions.Y) - overDraw.Y,
        (int)floor(bounding.MinEdge.Z / dimensions.Z) - overDraw.Z
    );

    irr::core::vector3d<int> newAabboxEnd(
        (int)ceil(bounding.MaxEdge.X / dimensions.X) + overDraw.X,
        (int)ceil(bounding.MaxEdge.Y / dimensions.Y) + overDraw.Y,
        (int)ceil(bounding.MaxEdge.Z / dimensions.Z) + overDraw.Z
    );

    if((newAabboxStart == aabboxStart && newAabboxEnd == aabboxEnd) && !dirty)
    {
        return;
    }

    aabboxStart = newAabboxStart;
    aabboxEnd = newAabboxEnd;

    Mesh->MeshBuffers.clear();

    irr::core::aabbox3df aabbox;

    irr::core::vector3d<int> chunkPos(0,0,0);

    dirty = false;

    for(int z = aabboxEnd.Z; z >= aabboxStart.Z; z--)
    {
        for(int x = aabboxEnd.X; x >= aabboxStart.X; x--)
        {
            for(int y = aabboxEnd.Y; y >= aabboxStart.Y; y--)
            {
                chunkPos.set(x,y,z);

                if(meshMap.find(chunkPos) == meshMap.end())
                {
                    meshMap[chunkPos] = ChunkMesh();
                    meshMap[chunkPos].Initialize(this, chunkPos);
                }

                aabbox = irr::core::aabbox3df(
                    ((int)dimensions.X * x), 
                    ((int)dimensions.Y * y), 
                    ((int)dimensions.Z * z),
                    ((int)dimensions.X * x + (int)dimensions.X), 
                    ((int)dimensions.Y * y + (int)dimensions.Y), 
                    ((int)dimensions.Z * z + (int)dimensions.Z)
                );

                if(AABBoxInFrustum(IRR.camera->getViewFrustum(), aabbox))
                {
                    if(chunkMap.find(chunkPos) != chunkMap.end()) { //Apparently checking a value is enough to generate an object
                        if(meshMap.find(chunkPos) == meshMap.end())
                        {
                            meshMap[chunkPos] = ChunkMesh();
                            meshMap[chunkPos].Initialize(this, chunkPos);
                        }

                        if(meshMap[chunkPos].Meshed)
                        {
                            Mesh->addMeshBuffer(meshMap[chunkPos].buffer);
                        }
                        if(!chunkMap[chunkPos].empty)
                        {
                            if(chunkMap[chunkPos].status == FILLED || chunkMap[chunkPos].status == DIRTY)
                            {
                                chunkMap[chunkPos].status = MESHING;
                                boost::threadpool::schedule(
                                    (*IRR.mThreadPool), 
                                    boost::threadpool::prio_task_func(10, boost::bind(&VoxelSceneNode::MeshBackground, this, chunkPos))
                                );
                            }
                        }
                        if(chunkMap[chunkPos].obstruct)
                        {
                            y = aabboxStart.Y;
                        }
                    }
                }
            }
        }
    }

    Mesh->recalculateBoundingBox();
    Mesh->setDirty();
}
void ProcessChunk(DWORD type, BYTE *data, DWORD size)
{
    struct chunk_types_S *p = chunk_table;

    while (p->type != 0xFFFFFFFF)
    {
        if (type == p->type)
        {
            if (p->max_size < size)
            {
                p->max_size = size;
            }
            if (p->min_size > size)
            {
                p->min_size = size;
            }
            p->count++;
            switch (type)
            {
            case W3D_CHUNK_MESH :
                ChunkMesh(data, size);
                break;
            case W3D_CHUNK_AGGREGATE_HEADER :
                ChunkAggregateHeader(data, size);
                break;
            case W3D_CHUNK_AGGREGATE_INFO :
                ChunkAggregateInfo(data, size);
                break;
            case W3D_CHUNK_AGGREGATE_CLASS_INFO :
                ChunkAggregateClassInfo(data, size);
                break;
            case W3D_CHUNK_MESH_USER_TEXT :
                ChunkMeshUserText(data, size);
                break;
            case O_W3D_CHUNK_MESH_HEADER :
                ChunkMeshHeader(data, size);
                break;
            case W3D_CHUNK_MESH_HEADER3 :
                ChunkMeshHeader3(data, size);
                break;
            case W3D_CHUNK_HIERARCHY_HEADER :
                ChunkHierarchyHeader(data, size);
                break;
            case W3D_CHUNK_ANIMATION_HEADER :
                ChunkAnimationHeader(data, size);
                break;
            case W3D_CHUNK_COMPRESSED_ANIMATION_HEADER :
                ChunkCompressedAnimHeader(data, size);
                break;
            case W3D_CHUNK_PIVOTS :
                ChunkPivot(data, size);
                break;
            case W3D_CHUNK_MORPHANIM_HEADER :
                ChunkMorphAnimHeader(data, size);
                break;
            case W3D_CHUNK_HMODEL_HEADER :
                ChunkHModelHeader(data, size);
                break;
            case W3D_CHUNK_NODE :
                ChunkHModelNode(data, size);
                break;
            case W3D_CHUNK_EMITTER_HEADER :
                ChunkEmitterHeader(data, size);
                break;
            case W3D_CHUNK_HLOD_HEADER :
                ChunkHLodHeader(data, size);
                break;
            case W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER :
                ChunkHLodArrayHeader(data, size);
                break;
            case W3D_CHUNK_HLOD_SUB_OBJECT :
                ChunkHLodSubObject(data, size);
                break;
            case W3D_CHUNK_BOX :
                ChunkBox(data, size);
                break;
            case W3D_CHUNK_TEXTURE_NAME :
                ChunkTextureName(data, size);
                break;

            case W3D_CHUNK_MATERIAL_INFO :
                break;

            // TODO:
            case W3D_CHUNK_AABTREE :
            case W3D_CHUNK_AABTREE_HEADER :
            case W3D_CHUNK_AABTREE_POLYINDICES :
            case W3D_CHUNK_AABTREE_NODES :
            case W3D_CHUNK_PIVOT_FIXUPS :
            case W3D_CHUNK_VERTICES :
            case W3D_CHUNK_VERTEX_NORMALS :
            case W3D_CHUNK_TRIANGLES :
            case W3D_CHUNK_VERTEX_SHADE_INDICES :
            case W3D_CHUNK_VERTEX_MATERIAL_NAME :
            case W3D_CHUNK_VERTEX_MATERIAL_INFO :
            case W3D_CHUNK_VERTEX_MAPPER_ARGS0 :
            case W3D_CHUNK_VERTEX_MAPPER_ARGS1 :
            case W3D_CHUNK_VERTEX_MATERIAL_IDS :
            case W3D_CHUNK_SHADER_IDS :
            case W3D_CHUNK_TEXTURE_STAGE :
            case W3D_CHUNK_TEXTURE_IDS :
            case W3D_CHUNK_TEXTURE_INFO :
            case W3D_CHUNK_STAGE_TEXCOORDS :
            case W3D_CHUNK_SHADERS :
            case W3D_CHUNK_DCG :
            case W3D_CHUNK_HLOD_PROXY_ARRAY :
                break;

            default :
                fprintf(outf, "%sWarning: WW3D Chunk Type 0x%08X skipped\n", Indent(), type);
                break;
            }
            return;
        }
        p++;
    }

    printf("*ERROR* Unrecognized Chunk Type %08X\n", type);
}