Browse Source

WIP: refactoring of chunk model generation

Kolja Strohm 2 years ago
parent
commit
d7a8195b58

+ 23 - 25
FactoryCraft/Block.cpp

@@ -21,7 +21,7 @@ Block::Block(const BlockType* zType,
 {
     hp = (float)maxHP;
     memset(sideVisible, 0, 6);
-    //Model3D::setAlpha(transparent);
+    // Model3D::setAlpha(transparent);
     Model3D::setPosition(
         (Framework::Vec3<float>)pos + Framework::Vec3<float>{0.5f, 0.5f, 0.5f});
     setModelDaten(model);
@@ -29,8 +29,7 @@ Block::Block(const BlockType* zType,
     memset(lightData, 0, 6 * 6);
 }
 
-Block::~Block()
-{}
+Block::~Block() {}
 
 void Block::beforeRender(
     GraphicsApi* api, Shader* zVertexShader, Shader* zPixelShader)
@@ -54,7 +53,7 @@ void Block::api(char* message)
             Model3D* mdl = World::INSTANCE->getCurrentTarget();
             if (mdl == this)
             {
-                if (partOfGround)
+                if (partOfModel)
                 {
                     World::INSTANCE->zSelectedEffectModel()->setDestroyedState(
                         1 - hp / maxHP);
@@ -65,21 +64,15 @@ void Block::api(char* message)
         }
     case 1: // model change
         {
-            bool affectsGround = partOfGround;
             ByteArrayReader reader(message + 1, 10000, 0);
             ModelInfo info(&reader);
             setModelDaten(info.getModel());
             setModelTextur(info.getTexture());
-            affectsGround |= info.getModelName().istGleich("cube")
-                          || info.getModelName().istGleich("grass");
-            if (affectsGround)
+            Chunk* zChunk = World::INSTANCE->zChunk(
+                World::INSTANCE->getChunkCenter(location.x, location.y));
+            if (zChunk)
             {
-                Chunk* zChunk = World::INSTANCE->zChunk(
-                    World::INSTANCE->getChunkCenter(location.x, location.y));
-                if (zChunk)
-                {
-                    zChunk->setGroundChanged();
-                }
+                zChunk->setModelChanged(this);
             }
             break;
         }
@@ -117,12 +110,15 @@ void Block::setLightData(Direction dir, unsigned char* data)
         sideVisible[getDirectionIndex(dir)] = 0;
     Chunk* zC = World::INSTANCE->zChunk(
         World::INSTANCE->getChunkCenter(location.x, location.y));
-    if (zC) zC->setLightChanged();
+    if (zC) zC->setLightChanged(partOfModel);
 }
 
-void Block::setPartOfGround(bool partOfGround)
+void Block::setPartOfModel(int type, bool part)
 {
-    this->partOfGround = partOfGround;
+    if (part)
+        this->partOfModel |= type;
+    else
+        this->partOfModel &= ~type;
 }
 
 const unsigned char* Block::getLightData(Direction dir) const
@@ -130,16 +126,17 @@ const unsigned char* Block::getLightData(Direction dir) const
     return lightData + getDirectionIndex(dir) * 6;
 }
 
-__int64 Block::getMaxLight() const {
+__int64 Block::getMaxLight() const
+{
     unsigned char max[6];
     max[0] = max[1] = max[2] = max[3] = max[4] = max[5] = 0;
     for (int i = 0; i < 6; i++)
     {
         for (int j = 0; j < 6; j++)
         {
-			if (lightData[i * 6 + j] > max[j]) max[j] = lightData[i * 6 + j];
-		}
-	}
+            if (lightData[i * 6 + j] > max[j]) max[j] = lightData[i * 6 + j];
+        }
+    }
     return ((__int64)max[0] << 24) | ((__int64)max[1] << 16)
          | ((__int64)max[2] << 8) | ((__int64)max[3] << 56)
          | ((__int64)max[4] << 48) | ((__int64)max[5] << 40);
@@ -148,8 +145,9 @@ __int64 Block::getMaxLight() const {
 bool Block::isVisible() const
 {
     return true;
-    //return sideVisible[0] || sideVisible[1] || sideVisible[2] || sideVisible[3]
-    //    || sideVisible[4] || sideVisible[5];
+    // return sideVisible[0] || sideVisible[1] || sideVisible[2] ||
+    // sideVisible[3]
+    //     || sideVisible[4] || sideVisible[5];
 }
 
 Vec3<int> Block::getLocation() const
@@ -250,7 +248,7 @@ Text Block::printLightInfo()
     return result;
 }
 
-bool Block::isPartOfGround() const
+int Block::getPartOfModels() const
 {
-    return partOfGround;
+    return partOfModel;
 }

+ 3 - 3
FactoryCraft/Block.h

@@ -22,7 +22,7 @@ protected:
     Vec3<int> location;
     unsigned char lightData[6 * 6];
     char needRequestModelInfo;
-    bool partOfGround;
+    int partOfModel;
 
     void beforeRender(
         GraphicsApi* api, Shader* zVertexShader, Shader* zPixelShader) override;
@@ -40,7 +40,7 @@ public:
     void api(char* message);
     void copyLightTo(Block* zB);
     void setLightData(Direction dir, unsigned char* data);
-    void setPartOfGround(bool partOfGround);
+    void setPartOfModel(int type, bool part);
     __int64 getMaxLight() const;
     const unsigned char* getLightData(Direction dir) const;
     bool isVisible() const;
@@ -50,5 +50,5 @@ public:
     Skeleton* zSkeleton() const;
     friend Chunk;
     Text printLightInfo();
-    bool isPartOfGround() const;
+    int getPartOfModels() const;
 };

+ 50 - 385
FactoryCraft/Chunk.cpp

@@ -2,6 +2,8 @@
 
 #include <Shader.h>
 
+#include "ChunkFluidModel.h"
+#include "ChunkGroundModel.h"
 #include "Constants.h"
 #include "CustomDX11API.h"
 #include "FactoryCraftModel.h"
@@ -16,7 +18,7 @@ Chunk::Chunk(Framework::Punkt location)
 {
     blocks = new Block*[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
     memset(blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(Block*));
-    groundModel = new FactoryCraftModel();
+    FactoryCraftModel* ground = new FactoryCraftModel();
     Model3DData* chunkModel
         = uiFactory.initParam.bildschirm->zGraphicsApi()->getModel(
             Text("chunk_ground_") + location.x + location.y);
@@ -30,17 +32,37 @@ Chunk::Chunk(Framework::Punkt location)
     chunkModel->setDiffusFactor(1.f);
     chunkModel->setSpecularFactor(0.f);
     chunkModel->setVertecies(0, 0);
-    groundModel->setModelDaten(chunkModel);
-    groundModel->setPosition(
+    ground->setModelDaten(chunkModel);
+    ground->setPosition(
         (float)location.x, (float)location.y, (float)WORLD_HEIGHT / 2.f);
-    groundModel->tick(0);
+    ground->tick(0);
+    groundModel = new ChunkGroundModel(ground, this);
+    FactoryCraftModel* fluids = new FactoryCraftModel();
+    chunkModel = uiFactory.initParam.bildschirm->zGraphicsApi()->getModel(
+        Text("chunk_fluids_") + location.x + location.y);
+    if (!chunkModel)
+    {
+        chunkModel
+            = uiFactory.initParam.bildschirm->zGraphicsApi()->createModel(
+                Text("chunk_fluids_") + location.x + location.y);
+    }
+    chunkModel->setAmbientFactor(0.f);
+    chunkModel->setDiffusFactor(1.f);
+    chunkModel->setSpecularFactor(0.f);
+    chunkModel->setVertecies(0, 0);
+    fluids->setModelDaten(chunkModel);
+    fluids->setPosition(
+        (float)location.x, (float)location.y, (float)WORLD_HEIGHT / 2.f);
+    fluids->tick(0);
+    fluidModel = new ChunkFluidModel(fluids, this);
 }
 
 Chunk::Chunk(Framework::Punkt location, Framework::StreamReader* zReader)
     : Chunk(location)
 {
     load(zReader);
-    buildGroundModel();
+    buildModel(groundModel);
+    buildModel(fluidModel);
 }
 
 Chunk::~Chunk()
@@ -254,388 +276,33 @@ void Chunk::load(Framework::StreamReader* zReader)
     isLoading = 0;
 }
 
-void Chunk::buildGroundModel()
+void Chunk::buildModel(ChunkModelBuilder* builder)
 {
     vcs.lock();
-    visibleBlocks.leeren();
-    lightChanged = 0;
-    Model3DData* chunkModel = groundModel->zModelData();
-    // remove old model
-    while (chunkModel->getPolygonAnzahl() > 0)
-    {
-        chunkModel->removePolygon(0);
-    }
-    // calculate verticies
-    Trie<GroundModelPart*> groundModelBuidler;
-    Array<GroundModelPart*> groundPartArray;
-    Vertex3D* groundVerticies = new Vertex3D[10000];
-    __int64* lightBuffer = new __int64[10000];
-    int groundVertexCount = 0;
-    int groundVertexArraySize = 10000;
-    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
-    {
-        if (blocks[i])
-        {
-            if (blocks[i]
-                    ->zBlockType()
-                    ->getModelInfo()
-                    .getModelName()
-                    .istGleich("cube"))
-            {
-                blocks[i]->setPartOfGround(1);
-                int index = 0;
-                for (Text* textureName :
-                    *blocks[i]->zBlockType()->getModelInfo().getTexturNames())
-                {
-                    Framework::Vec3<int> location(
-                        (i / WORLD_HEIGHT) / CHUNK_SIZE,
-                        (i / WORLD_HEIGHT) % CHUNK_SIZE,
-                        i % WORLD_HEIGHT);
-                    if (isPartOfGroundModel(location, index))
-                    {
-                        if (!groundModelBuidler.get(
-                                *textureName, textureName->getLength()))
-                        {
-                            GroundModelPart* part = new GroundModelPart();
-                            part->indexList = new int[10000];
-                            part->indexCount = 0;
-                            part->indexArraySize = 10000;
-                            part->name = *textureName;
-                            groundModelBuidler.set(
-                                *textureName, textureName->getLength(), part);
-                            groundPartArray.add(part);
-                        }
-                        GroundModelPart* part = groundModelBuidler.get(
-                            *textureName, textureName->getLength());
-                        const Vertex3D* vBuffer
-                            = blocks[i]->zModelData()->zVertexBuffer();
-                        Polygon3D* polygon
-                            = blocks[i]->zModelData()->getPolygon(index);
-                        if (part->indexCount + polygon->indexAnz
-                            > part->indexArraySize)
-                        {
-                            int* tmp = new int[part->indexArraySize + 10000];
-                            memcpy(tmp, part->indexList, part->indexCount * 4);
-                            delete[] part->indexList;
-                            part->indexList = tmp;
-                            part->indexArraySize += 10000;
-                        }
-                        if (groundVertexCount + polygon->indexAnz
-                            > groundVertexArraySize)
-                        {
-                            Vertex3D* tmp
-                                = new Vertex3D[groundVertexArraySize + 10000];
-                            memcpy(tmp,
-                                groundVerticies,
-                                groundVertexCount * sizeof(Vertex3D));
-                            delete[] groundVerticies;
-                            groundVerticies = tmp;
-                            groundVertexArraySize += 10000;
-                            __int64* lTmp = new __int64[groundVertexArraySize];
-                            memcpy(lTmp,
-                                lightBuffer,
-                                groundVertexCount * sizeof(__int64));
-                            delete[] lightBuffer;
-                            lightBuffer = lTmp;
-                        }
-                        for (int vi = 0; vi < polygon->indexAnz; vi++)
-                        {
-                            lightBuffer[groundVertexCount] = calculateLight(
-                                vBuffer[polygon->indexList[vi]].pos,
-                                location,
-                                getDirectionFromIndex(index));
-                            part->indexList[part->indexCount++]
-                                = groundVertexCount;
-                            groundVerticies[groundVertexCount++]
-                                = vBuffer[polygon->indexList[vi]];
-                            groundVerticies[groundVertexCount - 1].pos
-                                += blocks[i]->getPos()
-                                 - Vec3<float>((float)this->location.x,
-                                     (float)this->location.y,
-                                     (float)WORLD_HEIGHT / 2.f);
-                            groundVerticies[groundVertexCount - 1].id
-                                = groundVertexCount - 1;
-                        }
-                    }
-                    index++;
-                }
-            }
-            else if (blocks[i]
-                         ->zBlockType()
-                         ->getModelInfo()
-                         .getModelName()
-                         .istGleich("grass"))
-            {
-                blocks[i]->setPartOfGround(1);
-                __int64 light = blocks[i]->getMaxLight();
-                int index = 0;
-                for (Text* textureName :
-                    *blocks[i]->zBlockType()->getModelInfo().getTexturNames())
-                {
-                    if (!groundModelBuidler.get(
-                            *textureName, textureName->getLength()))
-                    {
-                        GroundModelPart* part = new GroundModelPart();
-                        part->indexList = new int[10000];
-                        part->indexCount = 0;
-                        part->indexArraySize = 10000;
-                        part->name = *textureName;
-                        groundModelBuidler.set(
-                            *textureName, textureName->getLength(), part);
-                        groundPartArray.add(part);
-                    }
-                    GroundModelPart* part = groundModelBuidler.get(
-                        *textureName, textureName->getLength());
-                    const Vertex3D* vBuffer
-                        = blocks[i]->zModelData()->zVertexBuffer();
-                    Polygon3D* polygon
-                        = blocks[i]->zModelData()->getPolygon(index);
-                    if (part->indexCount + polygon->indexAnz
-                        > part->indexArraySize)
-                    {
-                        int* tmp = new int[part->indexArraySize + 10000];
-                        memcpy(tmp, part->indexList, part->indexCount * 4);
-                        delete[] part->indexList;
-                        part->indexList = tmp;
-                        part->indexArraySize += 10000;
-                    }
-                    if (groundVertexCount + polygon->indexAnz
-                        > groundVertexArraySize)
-                    {
-                        Vertex3D* tmp
-                            = new Vertex3D[groundVertexArraySize + 10000];
-                        memcpy(tmp,
-                            groundVerticies,
-                            groundVertexCount * sizeof(Vertex3D));
-                        delete[] groundVerticies;
-                        groundVerticies = tmp;
-                        groundVertexArraySize += 10000;
-                        __int64* lTmp = new __int64[groundVertexArraySize];
-                        memcpy(lTmp,
-                            lightBuffer,
-                            groundVertexCount * sizeof(__int64));
-                        delete[] lightBuffer;
-                        lightBuffer = lTmp;
-                    }
-                    for (int vi = 0; vi < polygon->indexAnz; vi++)
-                    {
-                        lightBuffer[groundVertexCount] = light;
-                        part->indexList[part->indexCount++] = groundVertexCount;
-                        groundVerticies[groundVertexCount++]
-                            = vBuffer[polygon->indexList[vi]];
-                        groundVerticies[groundVertexCount - 1].pos
-                            += blocks[i]->getPos()
-                             - Vec3<float>((float)this->location.x,
-                                 (float)this->location.y,
-                                 (float)WORLD_HEIGHT / 2.f);
-                        groundVerticies[groundVertexCount - 1].id
-                            = groundVertexCount - 1;
-                    }
-                    index++;
-                }
-            }
-            else
-            {
-                blocks[i]->setPartOfGround(0);
-                visibleBlocks.add(blocks[i]);
-            }
-        }
-    }
-    Model3DTextur* textur = new Model3DTextur();
-    int pi = 0;
-    for (GroundModelPart* part : groundPartArray)
-    {
-        Polygon3D* polygon = new Polygon3D();
-        polygon->indexAnz = part->indexCount;
-        polygon->indexList = part->indexList;
-        groundModel->zModelData()->addPolygon(polygon);
-        textur->setPolygonTextur(pi,
-            uiFactory.initParam.bildschirm->zGraphicsApi()->createOrGetTextur(
-                part->name));
-        pi++;
-        delete part;
-    }
-    groundModel->zModelData()->setVertecies(groundVerticies, groundVertexCount);
-    groundModel->setModelTextur(textur);
-    groundModel->setVertexLightBuffer(lightBuffer, groundVertexCount);
+    modelChanged &= ~builder->getType();
+    lightChanged &= ~builder->getType();
+    builder->buildModel();
     vcs.unlock();
 }
 
-void Chunk::updateGroundLight()
+void Chunk::updateLight(ChunkModelBuilder* builder)
 {
     vcs.lock();
-    __int64* lightBuffer = groundModel->zLightBuffer();
-    int groundVertexCount = 0;
-    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
-    {
-        if (blocks[i])
-        {
-            if (blocks[i]
-                    ->zBlockType()
-                    ->getModelInfo()
-                    .getModelName()
-                    .istGleich("cube"))
-            {
-                int index = 0;
-                for (Text* textureName :
-                    *blocks[i]->zBlockType()->getModelInfo().getTexturNames())
-                {
-                    Framework::Vec3<int> location(
-                        (i / WORLD_HEIGHT) / CHUNK_SIZE,
-                        (i / WORLD_HEIGHT) % CHUNK_SIZE,
-                        i % WORLD_HEIGHT);
-                    if (isPartOfGroundModel(location, index))
-                    {
-                        const Vertex3D* vBuffer
-                            = blocks[i]->zModelData()->zVertexBuffer();
-                        Polygon3D* polygon
-                            = blocks[i]->zModelData()->getPolygon(index);
-                        for (int vi = 0; vi < polygon->indexAnz; vi++)
-                        {
-                            lightBuffer[groundVertexCount++] = calculateLight(
-                                vBuffer[polygon->indexList[vi]].pos,
-                                location,
-                                getDirectionFromIndex(index));
-                        }
-                    }
-                    index++;
-                }
-            }
-            else if (blocks[i]
-                         ->zBlockType()
-                         ->getModelInfo()
-                         .getModelName()
-                         .istGleich("grass"))
-            {
-                __int64 light = blocks[i]->getMaxLight();
-                int index = 0;
-                for (Text* textureName :
-                    *blocks[i]->zBlockType()->getModelInfo().getTexturNames())
-                {
-                    const Vertex3D* vBuffer
-                        = blocks[i]->zModelData()->zVertexBuffer();
-                    Polygon3D* polygon
-                        = blocks[i]->zModelData()->getPolygon(index);
-                    for (int vi = 0; vi < polygon->indexAnz; vi++)
-                    {
-                        lightBuffer[groundVertexCount++] = light;
-                    }
-                }
-            }
-        }
-    }
-    groundModel->copyLightToGPU();
+    lightChanged &= ~builder->getType();
+    builder->updateLightning();
     vcs.unlock();
 }
 
-__int64 Chunk::calculateLight(
-    Vec3<float> vertexPos, Vec3<int> blockPos, Direction direction)
-{
-    __int64 result = 0;
-    int sumCount = 1;
-    short lightSum[6];
-    Block* current = blocks[index(blockPos)];
-    const unsigned char* light = current->getLightData(direction);
-    for (int i = 0; i < 6; i++)
-    {
-        lightSum[i] = (short)light[i];
-    }
-    Vec3<int> vertexDirs(vertexPos.x < 0 ? -1 : 1,
-        vertexPos.y < 0 ? -1 : 1,
-        vertexPos.z < 0 ? -1 : 1);
-    Directions dirs = getDirectionsFromVector(vertexDirs) & ~direction;
-    Vec3<int> neighborDirs[3];
-    int neighborIndex = 0;
-    for (int i = 0; i < 6; i++)
-    {
-        Direction dir = getDirectionFromIndex(i);
-        if ((dirs | dir) == dirs)
-        {
-            neighborDirs[neighborIndex++] = getDirection(dir);
-            if (neighborIndex == 2) break;
-        }
-    }
-    neighborDirs[2] = neighborDirs[0] + neighborDirs[1];
-    for (int i = 0; i < 3; i++)
-    {
-        neighborDirs[i] += blockPos;
-        if (neighborDirs[i].x >= 0 && neighborDirs[i].y >= 0
-            && neighborDirs[i].z >= 0 && neighborDirs[i].x < CHUNK_SIZE
-            && neighborDirs[i].y < CHUNK_SIZE
-            && neighborDirs[i].z < WORLD_HEIGHT)
-        {
-            int neighborIndex = index(neighborDirs[i]);
-            Block* neighbor = blocks[neighborIndex];
-            if (neighbor)
-            {
-                const unsigned char* neighborLight
-                    = neighbor->getLightData(direction);
-                if ((neighborLight[0] | neighborLight[1] | neighborLight[2]
-                        | neighborLight[3] | neighborLight[4]
-                        | neighborLight[5])
-                    != 0)
-                {
-                    sumCount++;
-                    for (int j = 0; j < 6; j++)
-                    {
-                        lightSum[j] += (short)neighborLight[j];
-                    }
-                }
-            }
-        }
-        else
-        { // TODO: get light from neighbor chunk
-        }
-    }
-    for (int i = 0; i < 6; i++)
-    {
-        lightSum[i] = (lightSum[i] / sumCount) & 0xFF;
-    }
-    result = ((__int64)lightSum[0] << 24) | ((__int64)lightSum[1] << 16)
-           | ((__int64)lightSum[2] << 8) | ((__int64)lightSum[3] << 56)
-           | ((__int64)lightSum[4] << 48) | ((__int64)lightSum[5] << 40);
-    return result;
-}
-
-bool Chunk::isPartOfGroundModel(
-    Framework::Vec3<int> location, int directionIndex)
-{
-    Framework::Vec3<int> neighborLocation
-        = location + getDirection(getDirectionFromIndex(directionIndex));
-    bool needed = 0;
-    if (neighborLocation.x < 0 || neighborLocation.y < 0
-        || neighborLocation.z < 0 || neighborLocation.x >= CHUNK_SIZE
-        || neighborLocation.y >= CHUNK_SIZE
-        || neighborLocation.z >= WORLD_HEIGHT)
-    {
-        needed = 1;
-    }
-    else
-    {
-        int naighborIndex = index(neighborLocation);
-        if (!blocks[naighborIndex]
-            || !blocks[naighborIndex]
-                    ->zBlockType()
-                    ->getModelInfo()
-                    .getModelName()
-                    .istGleich("cube"))
-        {
-            needed = 1;
-        }
-    }
-    return needed;
-}
-
 void Chunk::renderSolid(std::function<void(Model3D*)> f)
 {
     vcs.lock();
     CustomDX11API* api
         = (CustomDX11API*)uiFactory.initParam.bildschirm->zGraphicsApi();
     api->setCullBack(false);
-    f(groundModel);
+    f(groundModel->zModel());
     api->setCullBack(true);
     float dist = 0.f;
-    if (api->isInFrustrum(groundModel->getPos(),
+    if (api->isInFrustrum(groundModel->zModel()->getPos(),
             (CHUNK_SIZE / 2.f, CHUNK_SIZE / 2.f, WORLD_HEIGHT / 2.f),
             &dist))
     {
@@ -653,17 +320,15 @@ bool Chunk::tick(std::function<void(Model3D*)> f, double time)
 {
     acs.lock();
     vcs.lock(); // TODO: enshure no dead lock occures
-    if (modelChanged)
-    {
-        modelChanged = 0;
-        buildGroundModel();
-    }
-    if (lightChanged)
-    {
-        lightChanged = 0;
-        updateGroundLight();
-    }
-    bool res = groundModel->tick(time);
+    if ((modelChanged | CombinedModels::GROUND) == modelChanged)
+        buildModel(groundModel);
+    if ((modelChanged | CombinedModels::FLUID) == modelChanged)
+        buildModel(fluidModel);
+    if ((lightChanged | CombinedModels::GROUND) == lightChanged)
+        updateLight(groundModel);
+    if ((lightChanged | CombinedModels::FLUID) == lightChanged)
+        updateLight(fluidModel);
+    bool res = groundModel->zModel()->tick(time);
     auto iterator = animations.begin();
     while (iterator)
     {
@@ -690,7 +355,7 @@ bool Chunk::tick(std::function<void(Model3D*)> f, double time)
 
 void Chunk::destroy()
 {
-    Model3DData* chunkModel = groundModel->zModelData();
+    Model3DData* chunkModel = groundModel->zModel()->zModelData();
     // remove old model
     while (chunkModel->getPolygonAnzahl() > 0)
     {
@@ -906,12 +571,12 @@ Framework::Vec3<int> Chunk::getMax() const
         location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT};
 }
 
-void Chunk::setGroundChanged()
+void Chunk::setModelChanged(int type)
 {
-    modelChanged = 1;
+    modelChanged |= type;
 }
 
-void Chunk::setLightChanged()
+void Chunk::setLightChanged(int type)
 {
-    lightChanged = 1;
+    lightChanged |= type;
 }

+ 18 - 17
FactoryCraft/Chunk.h

@@ -12,39 +12,38 @@
 #include "BlockAnimation.h"
 #include "Constants.h"
 #include "FactoryCraftModel.h"
+#include "ChunkModelBuilder.h"
 
-struct GroundModelPart
+class Chunk : public Framework::ReferenceCounter
+{
+public:
+static class CombinedModels
 {
-    int* indexList;
-    int indexCount;
-    int indexArraySize;
-    Text name;
+public:
+    static const int GROUND = 1;
+    static const int FLUID = 2;
 };
 
-class Chunk : public Framework::ReferenceCounter
-{
 private:
     Framework::Punkt location;
     // TODO: use native array for bedder performance?
     Block** blocks;
     Framework::Array<Block*> visibleBlocks;
-    FactoryCraftModel* groundModel;
+    ChunkModelBuilder* groundModel;
+    ChunkModelBuilder* fluidModel;
     bool isLoading;
     Framework::Critical cs;
     Framework::Critical vcs;
     Framework::Critical acs;
     Framework::RCArray<BlockAnimation> animations;
-    bool lightChanged;
-    bool modelChanged;
+    int lightChanged;
+    int modelChanged;
 
     void appendAnimation(
         Block* zB, int boneId, double time, Vec3<float> pos, Vec3<float> rot);
     void load(Framework::StreamReader* zReader);
-    void buildGroundModel();
-    void updateGroundLight();
-    __int64 calculateLight(
-        Vec3<float> vertexPos, Vec3<int> blockPos, Direction direction);
-    bool isPartOfGroundModel(Framework::Vec3<int> location, int directionIndex);
+    void buildModel(ChunkModelBuilder *builder);
+    void updateLight(ChunkModelBuilder *builder);
 
 public:
     Chunk(Framework::Punkt location);
@@ -64,12 +63,14 @@ public:
     Framework::Punkt getCenter() const;
     Framework::Vec3<int> getMin() const;
     Framework::Vec3<int> getMax() const;
-    void setGroundChanged();
-    void setLightChanged();
+    void setModelChanged(int modelType);
+    void setLightChanged(int modelType);
 
     inline static int index(Framework::Vec3<int> localLocation)
     {
         return (localLocation.x * CHUNK_SIZE + localLocation.y) * WORLD_HEIGHT
              + localLocation.z;
     }
+
+    friend ChunkModelBuilder;
 };

+ 11 - 0
FactoryCraft/ChunkFluidModel.h

@@ -0,0 +1,11 @@
+#pragma once
+
+#include "ChunkModelBuilder.h"
+
+class ChunkFluidModel : public ChunkModelBuilder
+{
+public:
+    ChunkFluidModel(FactoryCraftModel* target, Chunk* zChunk);
+    void buildModel() override;
+    bool updateLightning() override;
+};

+ 380 - 0
FactoryCraft/ChunkGroundModel.cpp

@@ -0,0 +1,380 @@
+#include "ChunkGroundModel.h"
+
+#include <Trie.h>
+
+#include "Area.h"
+#include "Block.h"
+#include "Constants.h"
+#include "FactoryCraftModel.h"
+#include "Globals.h"
+
+using namespace Framework;
+
+ChunkGroundModel::ChunkGroundModel(FactoryCraftModel* target, Chunk* zChunk)
+    : ChunkModelBuilder(target, zChunk, Chunk::CombinedModels::GROUND)
+{}
+
+__int64 ChunkGroundModel::calculateLight(Framework::Vec3<float> vertexPos,
+    Framework::Vec3<int> blockPos,
+    Direction direction)
+{
+    __int64 result = 0;
+    int sumCount = 1;
+    short lightSum[6];
+    Block* current = blocks()[Chunk::index(blockPos)];
+    const unsigned char* light = current->getLightData(direction);
+    for (int i = 0; i < 6; i++)
+    {
+        lightSum[i] = (short)light[i];
+    }
+    Vec3<int> vertexDirs(vertexPos.x < 0 ? -1 : 1,
+        vertexPos.y < 0 ? -1 : 1,
+        vertexPos.z < 0 ? -1 : 1);
+    Directions dirs = getDirectionsFromVector(vertexDirs) & ~direction;
+    Vec3<int> neighborDirs[3];
+    int neighborIndex = 0;
+    for (int i = 0; i < 6; i++)
+    {
+        Direction dir = getDirectionFromIndex(i);
+        if ((dirs | dir) == dirs)
+        {
+            neighborDirs[neighborIndex++] = getDirection(dir);
+            if (neighborIndex == 2) break;
+        }
+    }
+    neighborDirs[2] = neighborDirs[0] + neighborDirs[1];
+    for (int i = 0; i < 3; i++)
+    {
+        neighborDirs[i] += blockPos;
+        if (neighborDirs[i].x >= 0 && neighborDirs[i].y >= 0
+            && neighborDirs[i].z >= 0 && neighborDirs[i].x < CHUNK_SIZE
+            && neighborDirs[i].y < CHUNK_SIZE
+            && neighborDirs[i].z < WORLD_HEIGHT)
+        {
+            int neighborIndex = Chunk::index(neighborDirs[i]);
+            Block* neighbor = blocks()[neighborIndex];
+            if (neighbor)
+            {
+                const unsigned char* neighborLight
+                    = neighbor->getLightData(direction);
+                if ((neighborLight[0] | neighborLight[1] | neighborLight[2]
+                        | neighborLight[3] | neighborLight[4]
+                        | neighborLight[5])
+                    != 0)
+                {
+                    sumCount++;
+                    for (int j = 0; j < 6; j++)
+                    {
+                        lightSum[j] += (short)neighborLight[j];
+                    }
+                }
+            }
+        }
+        else
+        { // TODO: get light from neighbor chunk
+        }
+    }
+    for (int i = 0; i < 6; i++)
+    {
+        lightSum[i] = (lightSum[i] / sumCount) & 0xFF;
+    }
+    result = ((__int64)lightSum[0] << 24) | ((__int64)lightSum[1] << 16)
+           | ((__int64)lightSum[2] << 8) | ((__int64)lightSum[3] << 56)
+           | ((__int64)lightSum[4] << 48) | ((__int64)lightSum[5] << 40);
+    return result;
+}
+
+bool ChunkGroundModel::isPartOfGroundModel(
+    Framework::Vec3<int> location, int directionIndex)
+{
+    Framework::Vec3<int> neighborLocation
+        = location + getDirection(getDirectionFromIndex(directionIndex));
+    bool needed = 0;
+    if (neighborLocation.x < 0 || neighborLocation.y < 0
+        || neighborLocation.z < 0 || neighborLocation.x >= CHUNK_SIZE
+        || neighborLocation.y >= CHUNK_SIZE
+        || neighborLocation.z >= WORLD_HEIGHT)
+    {
+        needed = 1;
+    }
+    else
+    {
+        int naighborIndex = Chunk::index(neighborLocation);
+        if (!blocks()[naighborIndex]
+            || !blocks()[naighborIndex]
+                    ->zBlockType()
+                    ->getModelInfo()
+                    .getModelName()
+                    .istGleich("cube"))
+        {
+            needed = 1;
+        }
+    }
+    return needed;
+}
+
+void ChunkGroundModel::buildModel()
+{
+    Model3DData* chunkModel = target->zModelData();
+    // remove old model
+    while (chunkModel->getPolygonAnzahl() > 0)
+    {
+        chunkModel->removePolygon(0);
+    }
+    // calculate verticies
+    Trie<GroundModelPart*> groundModelBuidler;
+    Array<GroundModelPart*> groundPartArray;
+    Vertex3D* groundVerticies = new Vertex3D[10000];
+    __int64* lightBuffer = new __int64[10000];
+    int groundVertexCount = 0;
+    int groundVertexArraySize = 10000;
+    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
+    {
+        if (blocks()[i])
+        {
+            if (blocks()[i]
+                    ->zBlockType()
+                    ->getModelInfo()
+                    .getModelName()
+                    .istGleich("cube"))
+            {
+                setBlockPartOfModel(blocks()[i], 1);
+                int index = 0;
+                for (Text* textureName :
+                    *blocks()[i]->zBlockType()->getModelInfo().getTexturNames())
+                {
+                    Framework::Vec3<int> location(
+                        (i / WORLD_HEIGHT) / CHUNK_SIZE,
+                        (i / WORLD_HEIGHT) % CHUNK_SIZE,
+                        i % WORLD_HEIGHT);
+                    if (isPartOfGroundModel(location, index))
+                    {
+                        if (!groundModelBuidler.get(
+                                *textureName, textureName->getLength()))
+                        {
+                            GroundModelPart* part = new GroundModelPart();
+                            part->indexList = new int[10000];
+                            part->indexCount = 0;
+                            part->indexArraySize = 10000;
+                            part->name = *textureName;
+                            groundModelBuidler.set(
+                                *textureName, textureName->getLength(), part);
+                            groundPartArray.add(part);
+                        }
+                        GroundModelPart* part = groundModelBuidler.get(
+                            *textureName, textureName->getLength());
+                        const Vertex3D* vBuffer
+                            = blocks()[i]->zModelData()->zVertexBuffer();
+                        Polygon3D* polygon
+                            = blocks()[i]->zModelData()->getPolygon(index);
+                        if (part->indexCount + polygon->indexAnz
+                            > part->indexArraySize)
+                        {
+                            int* tmp = new int[part->indexArraySize + 10000];
+                            memcpy(tmp, part->indexList, part->indexCount * 4);
+                            delete[] part->indexList;
+                            part->indexList = tmp;
+                            part->indexArraySize += 10000;
+                        }
+                        if (groundVertexCount + polygon->indexAnz
+                            > groundVertexArraySize)
+                        {
+                            Vertex3D* tmp
+                                = new Vertex3D[groundVertexArraySize + 10000];
+                            memcpy(tmp,
+                                groundVerticies,
+                                groundVertexCount * sizeof(Vertex3D));
+                            delete[] groundVerticies;
+                            groundVerticies = tmp;
+                            groundVertexArraySize += 10000;
+                            __int64* lTmp = new __int64[groundVertexArraySize];
+                            memcpy(lTmp,
+                                lightBuffer,
+                                groundVertexCount * sizeof(__int64));
+                            delete[] lightBuffer;
+                            lightBuffer = lTmp;
+                        }
+                        for (int vi = 0; vi < polygon->indexAnz; vi++)
+                        {
+                            lightBuffer[groundVertexCount] = calculateLight(
+                                vBuffer[polygon->indexList[vi]].pos,
+                                location,
+                                getDirectionFromIndex(index));
+                            part->indexList[part->indexCount++]
+                                = groundVertexCount;
+                            groundVerticies[groundVertexCount++]
+                                = vBuffer[polygon->indexList[vi]];
+                            groundVerticies[groundVertexCount - 1].pos
+                                += blocks()[i]->getPos()
+                                 - Vec3<float>((float)chunkCenter().x,
+                                     (float)chunkCenter().y,
+                                     (float)WORLD_HEIGHT / 2.f);
+                            groundVerticies[groundVertexCount - 1].id
+                                = groundVertexCount - 1;
+                        }
+                    }
+                    index++;
+                }
+            }
+            else if (blocks()[i]
+                         ->zBlockType()
+                         ->getModelInfo()
+                         .getModelName()
+                         .istGleich("grass"))
+            {
+                setBlockPartOfModel(blocks()[i], 1);
+                __int64 light = blocks()[i]->getMaxLight();
+                int index = 0;
+                for (Text* textureName :
+                    *blocks()[i]->zBlockType()->getModelInfo().getTexturNames())
+                {
+                    if (!groundModelBuidler.get(
+                            *textureName, textureName->getLength()))
+                    {
+                        GroundModelPart* part = new GroundModelPart();
+                        part->indexList = new int[10000];
+                        part->indexCount = 0;
+                        part->indexArraySize = 10000;
+                        part->name = *textureName;
+                        groundModelBuidler.set(
+                            *textureName, textureName->getLength(), part);
+                        groundPartArray.add(part);
+                    }
+                    GroundModelPart* part = groundModelBuidler.get(
+                        *textureName, textureName->getLength());
+                    const Vertex3D* vBuffer
+                        = blocks()[i]->zModelData()->zVertexBuffer();
+                    Polygon3D* polygon
+                        = blocks()[i]->zModelData()->getPolygon(index);
+                    if (part->indexCount + polygon->indexAnz
+                        > part->indexArraySize)
+                    {
+                        int* tmp = new int[part->indexArraySize + 10000];
+                        memcpy(tmp, part->indexList, part->indexCount * 4);
+                        delete[] part->indexList;
+                        part->indexList = tmp;
+                        part->indexArraySize += 10000;
+                    }
+                    if (groundVertexCount + polygon->indexAnz
+                        > groundVertexArraySize)
+                    {
+                        Vertex3D* tmp
+                            = new Vertex3D[groundVertexArraySize + 10000];
+                        memcpy(tmp,
+                            groundVerticies,
+                            groundVertexCount * sizeof(Vertex3D));
+                        delete[] groundVerticies;
+                        groundVerticies = tmp;
+                        groundVertexArraySize += 10000;
+                        __int64* lTmp = new __int64[groundVertexArraySize];
+                        memcpy(lTmp,
+                            lightBuffer,
+                            groundVertexCount * sizeof(__int64));
+                        delete[] lightBuffer;
+                        lightBuffer = lTmp;
+                    }
+                    for (int vi = 0; vi < polygon->indexAnz; vi++)
+                    {
+                        lightBuffer[groundVertexCount] = light;
+                        part->indexList[part->indexCount++] = groundVertexCount;
+                        groundVerticies[groundVertexCount++]
+                            = vBuffer[polygon->indexList[vi]];
+                        groundVerticies[groundVertexCount - 1].pos
+                            += blocks()[i]->getPos()
+                             - Vec3<float>((float)chunkCenter().x,
+                                 (float)chunkCenter().y,
+                                 (float)WORLD_HEIGHT / 2.f);
+                        groundVerticies[groundVertexCount - 1].id
+                            = groundVertexCount - 1;
+                    }
+                    index++;
+                }
+            }
+            else
+            {
+                setBlockPartOfModel(blocks()[i], 0);
+            }
+        }
+    }
+    Model3DTextur* textur = new Model3DTextur();
+    int pi = 0;
+    for (GroundModelPart* part : groundPartArray)
+    {
+        Polygon3D* polygon = new Polygon3D();
+        polygon->indexAnz = part->indexCount;
+        polygon->indexList = part->indexList;
+        target->zModelData()->addPolygon(polygon);
+        textur->setPolygonTextur(pi,
+            uiFactory.initParam.bildschirm->zGraphicsApi()->createOrGetTextur(
+                part->name));
+        pi++;
+        delete part;
+    }
+    target->zModelData()->setVertecies(groundVerticies, groundVertexCount);
+    target->setModelTextur(textur);
+    target->setVertexLightBuffer(lightBuffer, groundVertexCount);
+}
+
+bool ChunkGroundModel::updateLightning() {
+    __int64* lightBuffer = target->zLightBuffer();
+    int groundVertexCount = 0;
+    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
+    {
+        if (blocks()[i])
+        {
+            if (blocks()[i]
+                    ->zBlockType()
+                    ->getModelInfo()
+                    .getModelName()
+                    .istGleich("cube"))
+            {
+                int index = 0;
+                for (Text* textureName :
+                    *blocks()[i]->zBlockType()->getModelInfo().getTexturNames())
+                {
+                    Framework::Vec3<int> location(
+                        (i / WORLD_HEIGHT) / CHUNK_SIZE,
+                        (i / WORLD_HEIGHT) % CHUNK_SIZE,
+                        i % WORLD_HEIGHT);
+                    if (isPartOfGroundModel(location, index))
+                    {
+                        const Vertex3D* vBuffer
+                            = blocks()[i]->zModelData()->zVertexBuffer();
+                        Polygon3D* polygon
+                            = blocks()[i]->zModelData()->getPolygon(index);
+                        for (int vi = 0; vi < polygon->indexAnz; vi++)
+                        {
+                            lightBuffer[groundVertexCount++] = calculateLight(
+                                vBuffer[polygon->indexList[vi]].pos,
+                                location,
+                                getDirectionFromIndex(index));
+                        }
+                    }
+                    index++;
+                }
+            }
+            else if (blocks()[i]
+                         ->zBlockType()
+                         ->getModelInfo()
+                         .getModelName()
+                         .istGleich("grass"))
+            {
+                __int64 light = blocks()[i]->getMaxLight();
+                int index = 0;
+                for (Text* textureName :
+                    *blocks()[i]->zBlockType()->getModelInfo().getTexturNames())
+                {
+                    const Vertex3D* vBuffer
+                        = blocks()[i]->zModelData()->zVertexBuffer();
+                    Polygon3D* polygon
+                        = blocks()[i]->zModelData()->getPolygon(index);
+                    for (int vi = 0; vi < polygon->indexAnz; vi++)
+                    {
+                        lightBuffer[groundVertexCount++] = light;
+                    }
+                }
+            }
+        }
+    }
+    target->copyLightToGPU();
+}

+ 16 - 0
FactoryCraft/ChunkGroundModel.h

@@ -0,0 +1,16 @@
+#pragma once
+#include "ChunkModelBuilder.h"
+
+class ChunkGroundModel : public ChunkModelBuilder
+{
+private:
+    __int64 calculateLight(Framework::Vec3<float> vertexPos,
+        Framework::Vec3<int> blockPos,
+        Direction direction);
+    bool isPartOfGroundModel(Framework::Vec3<int> location, int directionIndex);
+
+public:
+    ChunkGroundModel(FactoryCraftModel* target, Chunk* zChunk);
+    void buildModel() override;
+    bool updateLightning() override;
+};

+ 49 - 0
FactoryCraft/ChunkModelBuilder.cpp

@@ -0,0 +1,49 @@
+#include "ChunkModelBuilder.h"
+#include "Chunk.h"
+
+ChunkModelBuilder::ChunkModelBuilder(
+    FactoryCraftModel* target, Chunk* zChunk, int type)
+    : ReferenceCounter(),
+      zChunk(zChunk),
+      type(type),
+      target(target)
+{}
+
+ChunkModelBuilder::~ChunkModelBuilder()
+{
+    target->release();
+}
+
+Block** ChunkModelBuilder::blocks()
+{
+    return zChunk->blocks;
+}
+
+void ChunkModelBuilder::setBlockPartOfModel(Block* zBlock, bool partOfModel)
+{
+    int state = zBlock->getPartOfModels();
+    if (!state && partOfModel)
+    {
+        zChunk->visibleBlocks.removeValue(zBlock);
+    }
+    zBlock->setPartOfModel(type, partOfModel);
+    if (state && !zBlock->getPartOfModels())
+    {
+        zChunk->visibleBlocks.add(zBlock);
+    }
+}
+
+Framework::Punkt ChunkModelBuilder::chunkCenter()
+{
+    return zChunk->location;
+}
+
+FactoryCraftModel* ChunkModelBuilder::zModel() const
+{
+    return target;
+}
+
+int ChunkModelBuilder::getType() const
+{
+    return type;
+}

+ 38 - 0
FactoryCraft/ChunkModelBuilder.h

@@ -0,0 +1,38 @@
+#pragma once
+
+#include <ReferenceCounter.h>
+#include <Punkt.h>
+#include <Text.h>
+
+class Block;
+class Chunk;
+class FactoryCraftModel;
+
+struct GroundModelPart
+{
+    int* indexList;
+    int indexCount;
+    int indexArraySize;
+    Framework::Text name;
+};
+
+class ChunkModelBuilder : public Framework::ReferenceCounter
+{
+private:
+    Chunk* zChunk;
+    int type;
+
+protected:
+    FactoryCraftModel* target;
+    Block** blocks();
+    void setBlockPartOfModel(Block* zBlock, bool partOfModel);
+    Framework::Punkt chunkCenter();
+
+public:
+    ChunkModelBuilder(FactoryCraftModel* target, Chunk* zChunk, int type);
+    ~ChunkModelBuilder();
+    virtual void buildModel() = 0;
+    virtual bool updateLightning() = 0;
+    FactoryCraftModel* zModel() const;
+    int getType() const;
+};

+ 5 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -181,7 +181,9 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
     <ClCompile Include="ChatMessage.cpp" />
     <ClCompile Include="ChatOptions.cpp" />
     <ClCompile Include="Chunk.cpp" />
+    <ClCompile Include="ChunkGroundModel.cpp" />
     <ClCompile Include="ChunkMap.cpp" />
+    <ClCompile Include="ChunkModelBuilder.cpp" />
     <ClCompile Include="CraftingGrid.cpp" />
     <ClCompile Include="CraftingRecipies.cpp" />
     <ClCompile Include="CustomDX11API.cpp" />
@@ -233,7 +235,10 @@ copy "..\..\..\..\..\Allgemein\Network\x64\Release\Network.dll" "network.dll"</C
     <ClInclude Include="ChatMessage.h" />
     <ClInclude Include="ChatOptions.h" />
     <ClInclude Include="Chunk.h" />
+    <ClInclude Include="ChunkFluidModel.h" />
+    <ClInclude Include="ChunkGroundModel.h" />
     <ClInclude Include="ChunkMap.h" />
+    <ClInclude Include="ChunkModelBuilder.h" />
     <ClInclude Include="Constants.h" />
     <ClInclude Include="CraftingGrid.h" />
     <ClInclude Include="CraftingRecipies.h" />

+ 24 - 6
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -68,6 +68,9 @@
     <Filter Include="graphics\models">
       <UniqueIdentifier>{297bb4e2-25ec-423c-a588-7c8c1134d052}</UniqueIdentifier>
     </Filter>
+    <Filter Include="world\chunk">
+      <UniqueIdentifier>{de3c48f5-83e0-43ad-9eaa-fa31f2dd7a6a}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Main.cpp">
@@ -94,9 +97,6 @@
     <ClCompile Include="Block.cpp">
       <Filter>world</Filter>
     </ClCompile>
-    <ClCompile Include="Chunk.cpp">
-      <Filter>world</Filter>
-    </ClCompile>
     <ClCompile Include="Area.cpp">
       <Filter>world</Filter>
     </ClCompile>
@@ -223,6 +223,15 @@
     <ClCompile Include="FactoryCraftModel.cpp">
       <Filter>graphics\models</Filter>
     </ClCompile>
+    <ClCompile Include="Chunk.cpp">
+      <Filter>world\chunk</Filter>
+    </ClCompile>
+    <ClCompile Include="ChunkGroundModel.cpp">
+      <Filter>world\chunk</Filter>
+    </ClCompile>
+    <ClCompile Include="ChunkModelBuilder.cpp">
+      <Filter>world\chunk</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Area.h">
@@ -231,9 +240,6 @@
     <ClInclude Include="Block.h">
       <Filter>world</Filter>
     </ClInclude>
-    <ClInclude Include="Chunk.h">
-      <Filter>world</Filter>
-    </ClInclude>
     <ClInclude Include="Dimension.h">
       <Filter>world</Filter>
     </ClInclude>
@@ -384,6 +390,18 @@
     <ClInclude Include="FactoryCraftModel.h">
       <Filter>graphics\models</Filter>
     </ClInclude>
+    <ClInclude Include="Chunk.h">
+      <Filter>world\chunk</Filter>
+    </ClInclude>
+    <ClInclude Include="ChunkModelBuilder.h">
+      <Filter>world\chunk</Filter>
+    </ClInclude>
+    <ClInclude Include="ChunkGroundModel.h">
+      <Filter>world\chunk</Filter>
+    </ClInclude>
+    <ClInclude Include="ChunkFluidModel.h">
+      <Filter>world\chunk</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <FxCompile Include="DX11CustomVertexShader.hlsl">

+ 2 - 0
FactoryCraft/ModelInfo.h

@@ -11,6 +11,7 @@ private:
     Framework::Text modelPath;
     Framework::RCArray<Framework::Text> texturPaths;
     bool transparent;
+    int combinedModelTypes;
 
 public:
     ModelInfo(const char* model,
@@ -24,4 +25,5 @@ public:
     Framework::Text getModelName() const;
     const Framework::RCArray<Framework::Text>* getTexturNames() const;
     bool isTransparent() const;
+    int getCombinedModelTypes() const;
 };