mirror of
https://github.com/minetest/minetest.git
synced 2024-08-18 20:44:16 +02:00
work-in-progress texture atlas optimization
This commit is contained in:
parent
949383a2f7
commit
1704badc30
BIN
data/water.png
BIN
data/water.png
Binary file not shown.
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
@ -75,6 +75,7 @@ set(minetest_SRCS
|
||||
guiPauseMenu.cpp
|
||||
irrlichtwrapper.cpp
|
||||
client.cpp
|
||||
tile.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
|
@ -118,9 +118,9 @@ void Environment::step(float dtime)
|
||||
/*
|
||||
Apply water resistance
|
||||
*/
|
||||
if(player->in_water_stable)
|
||||
if(player->in_water_stable || player->in_water)
|
||||
{
|
||||
f32 max_down = 1.5*BS;
|
||||
f32 max_down = 2.0*BS;
|
||||
if(speed.Y < -max_down) speed.Y = -max_down;
|
||||
|
||||
f32 max = 2.5*BS;
|
||||
|
@ -21,6 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#define IIRRLICHTWRAPPER_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "texture.h"
|
||||
|
||||
/*
|
||||
NOTE: This is deprecated and should be removed completely
|
||||
*/
|
||||
|
||||
/*
|
||||
IrrlichtWrapper prototype.
|
||||
@ -38,15 +43,18 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// Should be called only from the main thread
|
||||
virtual IrrlichtDevice* getDevice(){ return NULL; }
|
||||
|
||||
virtual u32 getTime()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual textureid_t getTextureId(const std::string &name){ return 0; }
|
||||
/*virtual textureid_t getTextureId(const std::string &name){ return 0; }
|
||||
virtual std::string getTextureName(textureid_t id){ return ""; }
|
||||
virtual video::ITexture* getTexture(const std::string &name){ return NULL; }
|
||||
virtual video::ITexture* getTexture(const TextureSpec &spec){ return NULL; }
|
||||
virtual video::ITexture* getTexture(const TextureSpec &spec){ return NULL; }*/
|
||||
|
||||
private:
|
||||
};
|
||||
|
@ -96,13 +96,17 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is)
|
||||
#ifndef SERVER
|
||||
video::ITexture * MapBlockObjectItem::getImage()
|
||||
{
|
||||
//TODO
|
||||
|
||||
if(m_inventorystring.substr(0,3) == "Rat")
|
||||
//return g_device->getVideoDriver()->getTexture(porting::getDataPath("rat.png").c_str());
|
||||
return g_irrlicht->getTexture("rat.png");
|
||||
//return g_irrlicht->getTexture("rat.png");
|
||||
return NULL;
|
||||
|
||||
if(m_inventorystring.substr(0,4) == "Sign")
|
||||
//return g_device->getVideoDriver()->getTexture(porting::getDataPath("sign.png").c_str());
|
||||
return g_irrlicht->getTexture("sign.png");
|
||||
//return g_irrlicht->getTexture("sign.png");
|
||||
return NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -122,12 +122,9 @@ public:
|
||||
#ifndef SERVER
|
||||
video::ITexture * getImage()
|
||||
{
|
||||
/*if(m_content >= USEFUL_CONTENT_COUNT)
|
||||
return NULL;
|
||||
|
||||
return g_irrlicht->getTexture(g_content_inventory_texture_paths[m_content]);*/
|
||||
|
||||
return g_irrlicht->getTexture(content_features(m_content).inventory_texture);
|
||||
//TODO
|
||||
//return g_irrlicht->getTexture(content_features(m_content).inventory_texture);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
std::string getText()
|
||||
@ -264,7 +261,9 @@ public:
|
||||
name = "cloud.png";
|
||||
|
||||
// Get such a texture
|
||||
return g_irrlicht->getTexture(name);
|
||||
//return g_irrlicht->getTexture(name);
|
||||
//TODO
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
std::string getText()
|
||||
@ -351,10 +350,12 @@ public:
|
||||
std::ostringstream os;
|
||||
os<<"[progressbar"<<value_f;
|
||||
|
||||
TextureSpec spec;
|
||||
/*TextureSpec spec;
|
||||
spec.addTid(g_irrlicht->getTextureId(basename));
|
||||
spec.addTid(g_irrlicht->getTextureId(os.str()));
|
||||
return g_irrlicht->getTexture(spec);
|
||||
return g_irrlicht->getTexture(spec);*/
|
||||
//TODO
|
||||
return NULL;
|
||||
|
||||
/*// Make texture name for the new texture with a progress bar
|
||||
float value_f = (float)toolprogress / (float)maxprogress;
|
||||
|
@ -11,8 +11,22 @@ IrrlichtWrapper::IrrlichtWrapper(IrrlichtDevice *device)
|
||||
m_device = device;
|
||||
}
|
||||
|
||||
IrrlichtWrapper::~IrrlichtWrapper()
|
||||
{
|
||||
#if 0
|
||||
// Clear image cache
|
||||
for(core::map<std::string, video::IImage*>::Iterator
|
||||
i = m_imagecache.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
i.getNode()->getValue()->drop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void IrrlichtWrapper::Run()
|
||||
{
|
||||
#if 0
|
||||
/*
|
||||
Fetch textures
|
||||
*/
|
||||
@ -34,6 +48,7 @@ void IrrlichtWrapper::Run()
|
||||
|
||||
request.dest->push_back(result);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void IrrlichtWrapper::Shutdown(bool shutdown)
|
||||
@ -41,6 +56,18 @@ void IrrlichtWrapper::Shutdown(bool shutdown)
|
||||
m_running = !shutdown;
|
||||
}
|
||||
|
||||
IrrlichtDevice* IrrlichtWrapper::getDevice()
|
||||
{
|
||||
if(get_current_thread_id() != m_main_thread)
|
||||
{
|
||||
dstream<<"WARNING: IrrlichtWrapper::getDevice() called "
|
||||
"not from main thread"<<std::endl;
|
||||
return NULL;
|
||||
}
|
||||
return m_device;
|
||||
}
|
||||
|
||||
#if 0
|
||||
textureid_t IrrlichtWrapper::getTextureId(const std::string &name)
|
||||
{
|
||||
u32 id = m_namecache.getId(name);
|
||||
@ -55,9 +82,9 @@ std::string IrrlichtWrapper::getTextureName(textureid_t id)
|
||||
return name;
|
||||
}
|
||||
|
||||
video::ITexture* IrrlichtWrapper::getTexture(const std::string &name)
|
||||
video::ITexture* IrrlichtWrapper::getTexture(const std::string &filename)
|
||||
{
|
||||
TextureSpec spec(getTextureId(name));
|
||||
TextureSpec spec(getTextureId(filename));
|
||||
return getTexture(spec);
|
||||
}
|
||||
|
||||
@ -162,12 +189,36 @@ video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
|
||||
texture_name += "[";
|
||||
texture_name += name;
|
||||
texture_name += "]";
|
||||
|
||||
/*
|
||||
Try to get image from image cache
|
||||
*/
|
||||
{
|
||||
core::map<std::string, video::IImage*>::Node *n;
|
||||
n = m_imagecache.find(texture_name);
|
||||
if(n != NULL)
|
||||
{
|
||||
video::IImage *image = n->getValue();
|
||||
|
||||
core::dimension2d<u32> dim = image->getDimension();
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
image->copyTo(baseimg);
|
||||
|
||||
dstream<<"INFO: getTextureDirect(): Loaded \""
|
||||
<<texture_name<<"\" from image cache"
|
||||
<<std::endl;
|
||||
|
||||
// Do not process any further.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Stuff starting with [ are special commands
|
||||
if(name[0] != '[')
|
||||
{
|
||||
// A normal texture; load it from a file
|
||||
std::string path = porting::getDataPath(name.c_str());
|
||||
dstream<<"getTextureDirect(): Loading path \""<<path
|
||||
dstream<<"INFO: getTextureDirect(): Loading path \""<<path
|
||||
<<"\""<<std::endl;
|
||||
|
||||
// DEBUG
|
||||
@ -192,7 +243,7 @@ video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
|
||||
// If base image is NULL, load as base.
|
||||
if(baseimg == NULL)
|
||||
{
|
||||
dstream<<"Setting "<<name<<" as base"<<std::endl;
|
||||
dstream<<"INFO: Setting "<<name<<" as base"<<std::endl;
|
||||
/*
|
||||
Copy it this way to get an alpha channel.
|
||||
Otherwise images with alpha cannot be blitted on
|
||||
@ -209,7 +260,7 @@ video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
|
||||
// Else blit on base.
|
||||
else
|
||||
{
|
||||
dstream<<"Blitting "<<name<<" on base"<<std::endl;
|
||||
dstream<<"INFO: Blitting "<<name<<" on base"<<std::endl;
|
||||
// Size of the copied area
|
||||
core::dimension2d<u32> dim = image->getDimension();
|
||||
//core::dimension2d<u32> dim(16,16);
|
||||
@ -229,27 +280,85 @@ video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
|
||||
else
|
||||
{
|
||||
// A special texture modification
|
||||
dstream<<"getTextureDirect(): generating \""<<name<<"\""
|
||||
dstream<<"INFO: getTextureDirect(): generating \""<<name<<"\""
|
||||
<<std::endl;
|
||||
if(name.substr(0,6) == "[crack")
|
||||
{
|
||||
u16 progression = stoi(name.substr(6));
|
||||
// Size of the base image
|
||||
core::dimension2d<u32> dim(16, 16);
|
||||
core::dimension2d<u32> dim_base = baseimg->getDimension();
|
||||
// Crack will be drawn at this size
|
||||
u32 cracksize = 16;
|
||||
// Size of the crack image
|
||||
//core::dimension2d<u32> dim_crack(16, 16 * CRACK_ANIMATION_LENGTH);
|
||||
// Position to copy the crack to in the base image
|
||||
core::position2d<s32> pos_base(0, 0);
|
||||
core::dimension2d<u32> dim_crack(cracksize,cracksize);
|
||||
// Position to copy the crack from in the crack image
|
||||
core::position2d<s32> pos_other(0, 16 * progression);
|
||||
|
||||
video::IImage *crackimage = driver->createImageFromFile(
|
||||
porting::getDataPath("crack.png").c_str());
|
||||
crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
|
||||
core::rect<s32>(pos_other, dim),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);
|
||||
crackimage->drop();
|
||||
|
||||
if(crackimage)
|
||||
{
|
||||
/*crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
|
||||
core::rect<s32>(pos_other, dim_base),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);*/
|
||||
|
||||
for(u32 y0=0; y0<dim_base.Height/dim_crack.Height; y0++)
|
||||
for(u32 x0=0; x0<dim_base.Width/dim_crack.Width; x0++)
|
||||
{
|
||||
// Position to copy the crack to in the base image
|
||||
core::position2d<s32> pos_base(x0*cracksize, y0*cracksize);
|
||||
crackimage->copyToWithAlpha(baseimg, pos_base,
|
||||
core::rect<s32>(pos_other, dim_crack),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);
|
||||
}
|
||||
|
||||
crackimage->drop();
|
||||
}
|
||||
}
|
||||
else if(name.substr(0,8) == "[combine")
|
||||
{
|
||||
// "[combine:16x128:0,0=stone.png:0,16=grass.png"
|
||||
Strfnd sf(name);
|
||||
sf.next(":");
|
||||
u32 w0 = stoi(sf.next("x"));
|
||||
u32 h0 = stoi(sf.next(":"));
|
||||
dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
|
||||
core::dimension2d<u32> dim(w0,h0);
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
while(sf.atend() == false)
|
||||
{
|
||||
u32 x = stoi(sf.next(","));
|
||||
u32 y = stoi(sf.next("="));
|
||||
std::string filename = sf.next(":");
|
||||
dstream<<"INFO: Adding \""<<filename
|
||||
<<"\" to combined ("<<x<<","<<y<<")"
|
||||
<<std::endl;
|
||||
video::IImage *img = driver->createImageFromFile(
|
||||
porting::getDataPath(filename.c_str()).c_str());
|
||||
if(img)
|
||||
{
|
||||
core::dimension2d<u32> dim = img->getDimension();
|
||||
dstream<<"INFO: Size "<<dim.Width
|
||||
<<"x"<<dim.Height<<std::endl;
|
||||
core::position2d<s32> pos_base(x, y);
|
||||
video::IImage *img2 =
|
||||
driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
img->copyTo(img2);
|
||||
img->drop();
|
||||
img2->copyToWithAlpha(baseimg, pos_base,
|
||||
core::rect<s32>(v2s32(0,0), dim),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);
|
||||
img2->drop();
|
||||
}
|
||||
else
|
||||
{
|
||||
dstream<<"WARNING: img==NULL"<<std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(name.substr(0,12) == "[progressbar")
|
||||
{
|
||||
@ -262,12 +371,31 @@ video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
|
||||
" texture: \""<<name<<"\""<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Add to image cache
|
||||
*/
|
||||
if(baseimg != NULL)
|
||||
{
|
||||
core::map<std::string, video::IImage*>::Node *n;
|
||||
n = m_imagecache.find(texture_name);
|
||||
if(n != NULL)
|
||||
{
|
||||
video::IImage *img = n->getValue();
|
||||
if(img != baseimg)
|
||||
{
|
||||
img->drop();
|
||||
}
|
||||
}
|
||||
|
||||
m_imagecache[texture_name] = baseimg;
|
||||
}
|
||||
}
|
||||
|
||||
// If no resulting image, return NULL
|
||||
if(baseimg == NULL)
|
||||
{
|
||||
dstream<<"getTextureDirect(): baseimg is NULL (attempted to"
|
||||
dstream<<"WARNING: getTextureDirect(): baseimg is NULL (attempted to"
|
||||
" create texture \""<<texture_name<<"\""<<std::endl;
|
||||
return NULL;
|
||||
}
|
||||
@ -281,9 +409,8 @@ video::ITexture* IrrlichtWrapper::getTextureDirect(const TextureSpec &spec)
|
||||
|
||||
// Create texture from resulting image
|
||||
t = driver->addTexture(texture_name.c_str(), baseimg);
|
||||
baseimg->drop();
|
||||
|
||||
dstream<<"getTextureDirect(): created texture \""<<texture_name
|
||||
dstream<<"INFO: getTextureDirect(): created texture \""<<texture_name
|
||||
<<"\""<<std::endl;
|
||||
|
||||
return t;
|
||||
@ -321,5 +448,5 @@ void make_progressbar(float value, video::IImage *image)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -31,6 +31,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <jmutexautolock.h>
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
NOTE: This is deprecated and should be removed completely
|
||||
*/
|
||||
|
||||
/*
|
||||
A thread-safe texture pointer cache.
|
||||
|
||||
@ -38,45 +42,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
threads, because texture pointers have to be handled in
|
||||
background threads.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
class TextureCache
|
||||
{
|
||||
public:
|
||||
TextureCache()
|
||||
{
|
||||
m_mutex.Init();
|
||||
assert(m_mutex.IsInitialized());
|
||||
}
|
||||
|
||||
void set(std::string name, video::ITexture *texture)
|
||||
{
|
||||
if(texture == NULL)
|
||||
return;
|
||||
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
m_textures[name] = texture;
|
||||
}
|
||||
|
||||
video::ITexture* get(const std::string &name)
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
core::map<std::string, video::ITexture*>::Node *n;
|
||||
n = m_textures.find(name);
|
||||
|
||||
if(n != NULL)
|
||||
return n->getValue();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
core::map<std::string, video::ITexture*> m_textures;
|
||||
JMutex m_mutex;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
A thread-safe texture pointer cache
|
||||
*/
|
||||
@ -116,6 +83,7 @@ private:
|
||||
core::map<TextureSpec, video::ITexture*> m_textures;
|
||||
JMutex m_mutex;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
A thread-safe wrapper for irrlicht, to be accessed from
|
||||
@ -124,6 +92,8 @@ private:
|
||||
Queues tasks to be done in the main thread.
|
||||
|
||||
Also caches texture specification strings to ids and textures.
|
||||
|
||||
TODO: Remove this and move all texture functionality to TextureSource
|
||||
*/
|
||||
|
||||
class IrrlichtWrapper : public IIrrlichtWrapper
|
||||
@ -134,6 +104,8 @@ public:
|
||||
*/
|
||||
|
||||
IrrlichtWrapper(IrrlichtDevice *device);
|
||||
|
||||
~IrrlichtWrapper();
|
||||
|
||||
// Run queued tasks
|
||||
void Run();
|
||||
@ -141,6 +113,8 @@ public:
|
||||
// Shutdown wrapper; this disables queued texture fetching
|
||||
void Shutdown(bool shutdown);
|
||||
|
||||
IrrlichtDevice* getDevice();
|
||||
|
||||
/*
|
||||
These are called from other threads
|
||||
*/
|
||||
@ -151,7 +125,8 @@ public:
|
||||
{
|
||||
return m_device->getTimer()->getRealTime();
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Format of a texture name:
|
||||
"stone.png" (filename in image data directory)
|
||||
@ -167,20 +142,18 @@ public:
|
||||
// The reverse of the above
|
||||
std::string getTextureName(textureid_t id);
|
||||
// Gets a texture based on a filename
|
||||
video::ITexture* getTexture(const std::string &name);
|
||||
video::ITexture* getTexture(const std::string &filename);
|
||||
// Gets a texture based on a TextureSpec (a textureid_t is fine too)
|
||||
video::ITexture* getTexture(const TextureSpec &spec);
|
||||
#endif
|
||||
|
||||
private:
|
||||
/*
|
||||
Non-thread-safe variants of stuff, for internal use
|
||||
*/
|
||||
|
||||
// DEPRECATED NO-OP
|
||||
//video::ITexture* getTextureDirect(const std::string &spec);
|
||||
|
||||
// Constructs a texture according to spec
|
||||
video::ITexture* getTextureDirect(const TextureSpec &spec);
|
||||
//video::ITexture* getTextureDirect(const TextureSpec &spec);
|
||||
|
||||
/*
|
||||
Members
|
||||
@ -195,14 +168,19 @@ private:
|
||||
JMutex m_device_mutex;
|
||||
IrrlichtDevice *m_device;
|
||||
|
||||
#if 0
|
||||
// Queued texture fetches (to be processed by the main thread)
|
||||
RequestQueue<TextureSpec, video::ITexture*, u8, u8> m_get_texture_queue;
|
||||
|
||||
// Cache of textures by spec
|
||||
TextureCache m_texturecache;
|
||||
|
||||
// Cached or generated source images by texture name
|
||||
core::map<std::string, video::IImage*> m_imagecache;
|
||||
|
||||
// A mapping from texture id to string spec
|
||||
MutexedIdGenerator<std::string> m_namecache;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
19
src/main.cpp
19
src/main.cpp
@ -97,6 +97,9 @@ SUGG: Meshes of blocks could be split into 6 meshes facing into
|
||||
different directions and then only those drawn that need to be
|
||||
- Also an 1-dimensional tile map would be nice probably
|
||||
|
||||
SUGG: Calculate lighting per vertex to get a lighting effect like in
|
||||
bartwe's game
|
||||
|
||||
Gaming ideas:
|
||||
-------------
|
||||
|
||||
@ -363,8 +366,13 @@ Doing now (most important at the top):
|
||||
#include "guiMainMenu.h"
|
||||
#include "mineral.h"
|
||||
#include "noise.h"
|
||||
#include "tile.h"
|
||||
|
||||
IrrlichtWrapper *g_irrlicht;
|
||||
// TODO: Remove this
|
||||
IrrlichtWrapper *g_irrlicht = NULL;
|
||||
|
||||
// This makes textures
|
||||
TextureSource *g_texturesource = NULL;
|
||||
|
||||
MapDrawControl draw_control;
|
||||
|
||||
@ -1643,6 +1651,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
g_device = device;
|
||||
g_irrlicht = new IrrlichtWrapper(device);
|
||||
g_texturesource = new TextureSource(device);
|
||||
|
||||
/*
|
||||
Speed tests (done after irrlicht is loaded to get timer)
|
||||
@ -1670,7 +1679,8 @@ int main(int argc, char *argv[])
|
||||
video::IVideoDriver* driver = device->getVideoDriver();
|
||||
|
||||
/*
|
||||
This changes the minimum allowed number of vertices in a VBO
|
||||
This changes the minimum allowed number of vertices in a VBO.
|
||||
Default is 500.
|
||||
*/
|
||||
//driver->setMinHardwareBufferVertexCount(50);
|
||||
|
||||
@ -2061,6 +2071,11 @@ int main(int argc, char *argv[])
|
||||
*/
|
||||
g_irrlicht->Run();
|
||||
|
||||
/*
|
||||
Process TextureSource's queue
|
||||
*/
|
||||
g_texturesource->processQueue();
|
||||
|
||||
/*
|
||||
Random calculations
|
||||
*/
|
||||
|
@ -20,15 +20,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#ifndef MAIN_HEADER
|
||||
#define MAIN_HEADER
|
||||
|
||||
#include "irrlichtwrapper.h"
|
||||
|
||||
// Settings
|
||||
#include "utility.h"
|
||||
extern Settings g_settings;
|
||||
|
||||
// A thread safe wrapper to irrlicht
|
||||
// On a server build, this is always NULL.
|
||||
// TODO: Remove this
|
||||
#include "irrlichtwrapper.h"
|
||||
extern IrrlichtWrapper *g_irrlicht;
|
||||
|
||||
// This makes and maps textures
|
||||
#include "tile.h"
|
||||
extern TextureSource *g_texturesource;
|
||||
|
||||
// Debug streams
|
||||
|
||||
#include <fstream>
|
||||
|
91
src/map.cpp
91
src/map.cpp
@ -1974,7 +1974,7 @@ double tree_amount_2d(u64 seed, v2s16 p)
|
||||
{
|
||||
double noise = noise2d_perlin(
|
||||
0.5+(float)p.X/250, 0.5+(float)p.Y/250,
|
||||
seed+2, 5, 0.6);
|
||||
seed+2, 5, 0.66);
|
||||
double zeroval = -0.3;
|
||||
if(noise < zeroval)
|
||||
return 0;
|
||||
@ -2021,9 +2021,9 @@ double base_rock_level_2d(u64 seed, v2s16 p)
|
||||
base = base2;*/
|
||||
#if 1
|
||||
// Higher ground level
|
||||
double higher = (double)WATER_LEVEL + 13. + 50. * noise2d_perlin(
|
||||
0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
|
||||
seed+85039, 6, 0.69);
|
||||
double higher = (double)WATER_LEVEL + 25. + 45. * noise2d_perlin(
|
||||
0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
|
||||
seed+85039, 5, 0.69);
|
||||
//higher = 30; // For debugging
|
||||
|
||||
// Limit higher to at least base
|
||||
@ -2042,7 +2042,7 @@ double base_rock_level_2d(u64 seed, v2s16 p)
|
||||
//double b = 20;
|
||||
|
||||
// Offset to more low
|
||||
double a_off = -0.3;
|
||||
double a_off = -0.15;
|
||||
// High/low selector
|
||||
/*double a = 0.5 + b * (a_off + noise2d_perlin(
|
||||
0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
|
||||
@ -2414,12 +2414,12 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
|
||||
/*
|
||||
Make dungeons
|
||||
*/
|
||||
//u32 dungeons_count = relative_volume / 600000;
|
||||
/*u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
|
||||
u32 dungeons_count = relative_volume / 600000;
|
||||
u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
|
||||
if(stone_surface_max_y < WATER_LEVEL)
|
||||
bruises_count = 0;*/
|
||||
u32 dungeons_count = 0;
|
||||
u32 bruises_count = 0;
|
||||
bruises_count = 0;
|
||||
/*u32 dungeons_count = 0;
|
||||
u32 bruises_count = 0;*/
|
||||
for(u32 jj=0; jj<dungeons_count+bruises_count; jj++)
|
||||
{
|
||||
s16 min_tunnel_diameter = 2;
|
||||
@ -5116,6 +5116,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
timecheck_counter++;
|
||||
if(timecheck_counter > 50)
|
||||
{
|
||||
timecheck_counter = 0;
|
||||
int time2 = time(0);
|
||||
if(time2 > time1 + 4)
|
||||
{
|
||||
@ -5167,71 +5168,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 0
|
||||
v3s16 blockpos_nodes = block->getPosRelative();
|
||||
|
||||
// Block center position
|
||||
v3f blockpos(
|
||||
((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
|
||||
((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
|
||||
((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
|
||||
);
|
||||
|
||||
// Block position relative to camera
|
||||
v3f blockpos_relative = blockpos - camera_position;
|
||||
|
||||
// Distance in camera direction (+=front, -=back)
|
||||
f32 dforward = blockpos_relative.dotProduct(camera_direction);
|
||||
|
||||
// Total distance
|
||||
f32 d = blockpos_relative.getLength();
|
||||
|
||||
if(m_control.range_all == false)
|
||||
{
|
||||
// If block is far away, don't draw it
|
||||
if(d > m_control.wanted_range * BS)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Maximum radius of a block
|
||||
f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
|
||||
|
||||
// If block is (nearly) touching the camera, don't
|
||||
// bother validating further (that is, render it anyway)
|
||||
if(d > block_max_radius * 1.5)
|
||||
{
|
||||
// Cosine of the angle between the camera direction
|
||||
// and the block direction (camera_direction is an unit vector)
|
||||
f32 cosangle = dforward / d;
|
||||
|
||||
// Compensate for the size of the block
|
||||
// (as the block has to be shown even if it's a bit off FOV)
|
||||
// This is an estimate.
|
||||
cosangle += block_max_radius / dforward;
|
||||
|
||||
// If block is not in the field of view, skip it
|
||||
//if(cosangle < cos(FOV_ANGLE/2))
|
||||
if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
v3s16 blockpos_nodes = block->getPosRelative();
|
||||
|
||||
// Block center position
|
||||
v3f blockpos(
|
||||
((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
|
||||
((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
|
||||
((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
|
||||
);
|
||||
|
||||
// Block position relative to camera
|
||||
v3f blockpos_relative = blockpos - camera_position;
|
||||
|
||||
// Total distance
|
||||
f32 d = blockpos_relative.getLength();
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
/*
|
||||
Update expired mesh
|
||||
@ -5324,6 +5260,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
// Render transparent on transparent pass and likewise.
|
||||
if(transparent == is_transparent_pass)
|
||||
{
|
||||
/*
|
||||
This *shouldn't* hurt too much because Irrlicht
|
||||
doesn't change opengl textures if the old
|
||||
material is set again.
|
||||
*/
|
||||
driver->setMaterial(buf->getMaterial());
|
||||
driver->drawMeshBuffer(buf);
|
||||
vertex_count += buf->getVertexCount();
|
||||
|
@ -513,6 +513,8 @@ public:
|
||||
// For debug printing
|
||||
virtual void PrintInfo(std::ostream &out);
|
||||
|
||||
bool isSavingEnabled(){ return m_map_saving_enabled; }
|
||||
|
||||
private:
|
||||
// Seed used for all kinds of randomness
|
||||
u64 m_seed;
|
||||
|
192
src/mapblock.cpp
192
src/mapblock.cpp
@ -273,13 +273,32 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
|
||||
video::SColor c = video::SColor(alpha,li,li,li);
|
||||
|
||||
face.vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c,
|
||||
core::vector2d<f32>(0,1));
|
||||
face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c,
|
||||
core::vector2d<f32>(abs_scale,1));
|
||||
face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c,
|
||||
core::vector2d<f32>(0,1));
|
||||
face.vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c,
|
||||
core::vector2d<f32>(abs_scale,0));
|
||||
face.vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c,
|
||||
core::vector2d<f32>(0,0));
|
||||
face.vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c,
|
||||
core::vector2d<f32>(abs_scale,0));
|
||||
|
||||
/*float x0 = (float)tile.tx/256.0;
|
||||
float y0 = (float)tile.ty/256.0;
|
||||
float w = ((float)tile.tw + 1.0)/256.0;
|
||||
float h = ((float)tile.th + 1.0)/256.0;*/
|
||||
|
||||
float x0 = tile.texture.pos.X;
|
||||
float y0 = tile.texture.pos.Y;
|
||||
float w = tile.texture.size.X;
|
||||
float h = tile.texture.size.Y;
|
||||
|
||||
face.vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c,
|
||||
core::vector2d<f32>(x0+w*abs_scale, y0+h));
|
||||
face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c,
|
||||
core::vector2d<f32>(x0, y0+h));
|
||||
face.vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c,
|
||||
core::vector2d<f32>(x0, y0));
|
||||
face.vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c,
|
||||
core::vector2d<f32>(x0+w*abs_scale, y0));
|
||||
|
||||
face.tile = tile;
|
||||
//DEBUG
|
||||
@ -318,11 +337,26 @@ TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
|
||||
}
|
||||
if(mod.type == NODEMOD_CRACK)
|
||||
{
|
||||
/*
|
||||
Get texture id, translate it to name, append stuff to
|
||||
name, get texture id
|
||||
*/
|
||||
// Get original texture name
|
||||
u32 orig_id = spec.texture.id;
|
||||
std::string orig_name = g_texturesource->getTextureName(orig_id);
|
||||
// Create new texture name
|
||||
std::ostringstream os;
|
||||
os<<"[crack"<<mod.param;
|
||||
|
||||
textureid_t tid = g_irrlicht->getTextureId(os.str());
|
||||
spec.spec.addTid(tid);
|
||||
os<<orig_name<<"^[crack"<<mod.param;
|
||||
//os<<orig_name<<"^[progressbar0.5";
|
||||
//os<<"mese.png";
|
||||
// Get new texture
|
||||
u32 new_id = g_texturesource->getTextureId(os.str());
|
||||
|
||||
dstream<<"MapBlock::getNodeTile(): Switching from "
|
||||
<<orig_name<<" to "<<os.str()<<" ("
|
||||
<<orig_id<<" to "<<new_id<<")"<<std::endl;
|
||||
|
||||
spec.texture = g_texturesource->getTexture(new_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,7 +440,9 @@ void MapBlock::updateFastFaceRow(
|
||||
TileSpec tile0_next;
|
||||
TileSpec tile1_next;
|
||||
u8 light_next = 0;
|
||||
|
||||
|
||||
// If at last position, there is nothing to compare to and
|
||||
// the face must be drawn anyway
|
||||
if(j != length - 1)
|
||||
{
|
||||
p_next = p + translate_dir;
|
||||
@ -426,7 +462,31 @@ void MapBlock::updateFastFaceRow(
|
||||
|
||||
continuous_tiles_count++;
|
||||
|
||||
if(next_is_different)
|
||||
// This is set to true if the texture doesn't allow more tiling
|
||||
bool end_of_texture = false;
|
||||
/*
|
||||
If there is no texture, it can be tiled infinitely.
|
||||
If tiled==0, it means the texture can be tiled infinitely.
|
||||
Otherwise check tiled agains continuous_tiles_count.
|
||||
|
||||
This check has to be made for both tiles, because this is
|
||||
a bit hackish and we know which one we're using only when
|
||||
the decision to make the faces is made.
|
||||
*/
|
||||
if(tile0.texture.atlas != NULL && tile0.texture.tiled != 0)
|
||||
{
|
||||
if(tile0.texture.tiled <= continuous_tiles_count)
|
||||
end_of_texture = true;
|
||||
}
|
||||
if(tile1.texture.atlas != NULL && tile1.texture.tiled != 0)
|
||||
{
|
||||
if(tile1.texture.tiled <= continuous_tiles_count)
|
||||
end_of_texture = true;
|
||||
}
|
||||
|
||||
//end_of_texture = true; //DEBUG
|
||||
|
||||
if(next_is_different || end_of_texture)
|
||||
{
|
||||
/*
|
||||
Create a face if there should be one
|
||||
@ -684,10 +744,6 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
Convert FastFaces to SMesh
|
||||
*/
|
||||
|
||||
scene::SMesh *mesh_new = NULL;
|
||||
|
||||
mesh_new = new scene::SMesh();
|
||||
|
||||
MeshCollector collector;
|
||||
|
||||
if(fastfaces_new.size() > 0)
|
||||
@ -708,8 +764,9 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
FastFace &f = fastfaces_new[i];
|
||||
|
||||
const u16 indices[] = {0,1,2,2,3,0};
|
||||
|
||||
video::ITexture *texture = g_irrlicht->getTexture(f.tile.spec);
|
||||
|
||||
//video::ITexture *texture = g_irrlicht->getTexture(f.tile.spec);
|
||||
video::ITexture *texture = f.tile.texture.atlas;
|
||||
if(texture == NULL)
|
||||
continue;
|
||||
|
||||
@ -717,11 +774,6 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
|
||||
f.tile.applyMaterialOptions(material);
|
||||
|
||||
/*if(f.tile.alpha != 255)
|
||||
material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
else
|
||||
material.MaterialType = video::EMT_SOLID;*/
|
||||
|
||||
collector.append(material, f.vertices, 4, indices, 6);
|
||||
}
|
||||
}
|
||||
@ -742,7 +794,11 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
material_water1.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_water1.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_water1.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
material_water1.setTexture(0, g_irrlicht->getTexture("water.png"));
|
||||
//TODO
|
||||
//material_water1.setTexture(0, g_irrlicht->getTexture("water.png"));
|
||||
AtlasPointer pa_water1 = g_texturesource->getTexture(
|
||||
g_texturesource->getTextureId("water.png"));
|
||||
material_water1.setTexture(0, pa_water1.atlas);
|
||||
|
||||
// New-style leaves material
|
||||
video::SMaterial material_leaves1;
|
||||
@ -751,7 +807,11 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
material_leaves1.setTexture(0, g_irrlicht->getTexture("leaves.png"));
|
||||
//TODO
|
||||
//material_leaves1.setTexture(0, g_irrlicht->getTexture("leaves.png"));
|
||||
AtlasPointer pa_leaves1 = g_texturesource->getTexture(
|
||||
g_texturesource->getTextureId("leaves.png"));
|
||||
material_leaves1.setTexture(0, pa_leaves1.atlas);
|
||||
|
||||
for(s16 z=0; z<MAP_BLOCKSIZE; z++)
|
||||
for(s16 y=0; y<MAP_BLOCKSIZE; y++)
|
||||
@ -804,7 +864,8 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
if(dir == v3s16(0,-1,0))
|
||||
//TODO
|
||||
/*if(dir == v3s16(0,-1,0))
|
||||
material.setTexture(0,
|
||||
g_irrlicht->getTexture("torch_on_floor.png"));
|
||||
else if(dir == v3s16(0,1,0))
|
||||
@ -816,7 +877,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
g_irrlicht->getTexture("torch_on_floor.png"));
|
||||
else
|
||||
material.setTexture(0,
|
||||
g_irrlicht->getTexture("torch.png"));
|
||||
g_irrlicht->getTexture("torch.png"));*/
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
@ -974,14 +1035,18 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
/*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
|
||||
/*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
|
||||
video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
|
||||
pa_water1.x0(), pa_water1.y1()),
|
||||
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
|
||||
pa_water1.x1(), pa_water1.y1()),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_water1.x1(), pa_water1.y0()),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_water1.x0(), pa_water1.y0()),
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1048,10 +1113,18 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
{
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
|
||||
/*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
|
||||
video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
|
||||
pa_water1.x0(), pa_water1.y1()),
|
||||
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
|
||||
pa_water1.x1(), pa_water1.y1()),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_water1.x1(), pa_water1.y0()),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_water1.x0(), pa_water1.y0()),
|
||||
};
|
||||
|
||||
for(s32 i=0; i<4; i++)
|
||||
@ -1092,10 +1165,18 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
|
||||
/*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
|
||||
video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
|
||||
pa_water1.x0(), pa_water1.y1()),
|
||||
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
|
||||
pa_water1.x1(), pa_water1.y1()),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_water1.x1(), pa_water1.y0()),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_water1.x0(), pa_water1.y0()),
|
||||
};
|
||||
|
||||
for(s32 i=0; i<4; i++)
|
||||
@ -1120,10 +1201,18 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
{
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
|
||||
/*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
|
||||
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
|
||||
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
|
||||
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),
|
||||
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
|
||||
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
|
||||
pa_leaves1.x0(), pa_leaves1.y1()),
|
||||
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
|
||||
pa_leaves1.x1(), pa_leaves1.y1()),
|
||||
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
|
||||
pa_leaves1.x1(), pa_leaves1.y0()),
|
||||
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
|
||||
pa_leaves1.x0(), pa_leaves1.y0()),
|
||||
};
|
||||
|
||||
if(j == 0)
|
||||
@ -1173,6 +1262,9 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
Add stuff from collector to mesh
|
||||
*/
|
||||
|
||||
scene::SMesh *mesh_new = NULL;
|
||||
mesh_new = new scene::SMesh();
|
||||
|
||||
collector.fillMesh(mesh_new);
|
||||
|
||||
/*
|
||||
@ -1191,13 +1283,25 @@ void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
mesh_new = NULL;
|
||||
}
|
||||
|
||||
// Use VBO for mesh (this just would set this for ever buffer)
|
||||
// This will lead to infinite memory usage because or irrlicht.
|
||||
//mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
|
||||
|
||||
/*std::cout<<"MapBlock has "<<fastfaces_new.size()<<" faces "
|
||||
<<"and uses "<<mesh_new->getMeshBufferCount()
|
||||
<<" materials (meshbuffers)"<<std::endl;*/
|
||||
if(mesh_new)
|
||||
{
|
||||
#if 0
|
||||
// Usually 1-700 faces and 1-7 materials
|
||||
std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
|
||||
<<"and uses "<<mesh_new->getMeshBufferCount()
|
||||
<<" materials (meshbuffers)"<<std::endl;
|
||||
#endif
|
||||
|
||||
// Use VBO for mesh (this just would set this for ever buffer)
|
||||
// This will lead to infinite memory usage because or irrlicht.
|
||||
//mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
|
||||
|
||||
/*
|
||||
NOTE: If that is enabled, some kind of a queue to the main
|
||||
thread should be made which would call irrlicht to delete
|
||||
the hardware buffer and then delete the mesh
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
Replace the mesh
|
||||
|
124
src/mapnode.cpp
124
src/mapnode.cpp
@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "mapnode.h"
|
||||
#include "tile.h"
|
||||
#include "porting.h"
|
||||
@ -31,6 +32,20 @@ ContentFeatures::~ContentFeatures()
|
||||
delete translate_to;
|
||||
}
|
||||
|
||||
void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha)
|
||||
{
|
||||
if(g_texturesource)
|
||||
{
|
||||
tiles[i].texture = g_texturesource->getTexture(name);
|
||||
}
|
||||
|
||||
if(alpha != 255)
|
||||
{
|
||||
tiles[i].alpha = alpha;
|
||||
tiles[i].material_type = MATERIAL_ALPHA_VERTEX;
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentFeatures g_content_features[256];
|
||||
|
||||
ContentFeatures & content_features(u8 i)
|
||||
@ -40,56 +55,75 @@ ContentFeatures & content_features(u8 i)
|
||||
|
||||
void init_mapnode(IIrrlichtWrapper *irrlicht)
|
||||
{
|
||||
// Read some settings
|
||||
bool new_style_water = g_settings.getBool("new_style_water");
|
||||
bool new_style_leaves = g_settings.getBool("new_style_leaves");
|
||||
|
||||
/*
|
||||
Initialize content feature table
|
||||
*/
|
||||
|
||||
/*
|
||||
Set initial material type to same in all tiles, so that the
|
||||
same material can be used in more stuff.
|
||||
This is set according to the leaves because they are the only
|
||||
differing material to which all materials can be changed to
|
||||
get this optimization.
|
||||
*/
|
||||
u8 initial_material_type = MATERIAL_ALPHA_SIMPLE;
|
||||
/*if(new_style_leaves)
|
||||
initial_material_type = MATERIAL_ALPHA_SIMPLE;
|
||||
else
|
||||
initial_material_type = MATERIAL_ALPHA_NONE;*/
|
||||
for(u16 i=0; i<256; i++)
|
||||
{
|
||||
ContentFeatures *f = &g_content_features[i];
|
||||
for(u16 j=0; j<6; j++)
|
||||
f->tiles[j].material_type = initial_material_type;
|
||||
}
|
||||
|
||||
u8 i;
|
||||
ContentFeatures *f = NULL;
|
||||
|
||||
i = CONTENT_STONE;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures(irrlicht->getTextureId("stone.png"));
|
||||
f->setAllTextures("stone.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_GRASS;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures(TextureSpec(irrlicht->getTextureId("mud.png"),
|
||||
irrlicht->getTextureId("grass_side.png")));
|
||||
f->setTexture(0, irrlicht->getTextureId("grass.png"));
|
||||
f->setTexture(1, irrlicht->getTextureId("mud.png"));
|
||||
f->setInventoryTexture(irrlicht->getTextureId("grass.png"));
|
||||
f->setAllTextures("mud.png^grass_side.png");
|
||||
f->setTexture(0, "grass.png");
|
||||
f->setTexture(1, "mud.png");
|
||||
//f->setInventoryTexture(irrlicht->getTextureId("grass.png"));
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_GRASS_FOOTSTEPS;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures(TextureSpec(irrlicht->getTextureId("mud.png"),
|
||||
irrlicht->getTextureId("grass_side.png")));
|
||||
f->setTexture(0, irrlicht->getTextureId("grass_footsteps.png"));
|
||||
f->setTexture(1, irrlicht->getTextureId("mud.png"));
|
||||
f->setInventoryTexture(irrlicht->getTextureId("grass_footsteps.png"));
|
||||
//f->setInventoryTexture(irrlicht->getTextureId("grass_footsteps.png"));
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_MUD;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures(irrlicht->getTextureId("mud.png"));
|
||||
f->setAllTextures("mud.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_SAND;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures(irrlicht->getTextureId("sand.png"));
|
||||
f->setAllTextures("sand.png");
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_TREE;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures(irrlicht->getTextureId("tree.png"));
|
||||
f->setTexture(0, irrlicht->getTextureId("tree_top.png"));
|
||||
f->setTexture(1, irrlicht->getTextureId("tree_top.png"));
|
||||
f->setInventoryTexture(irrlicht->getTextureId("tree_top.png"));
|
||||
f->setAllTextures("tree.png");
|
||||
f->setTexture(0, "tree_top.png");
|
||||
f->setTexture(1, "tree_top.png");
|
||||
//f->setInventoryTexture(irrlicht->getTextureId("tree_top.png"));
|
||||
f->param_type = CPT_MINERAL;
|
||||
f->is_ground_content = true;
|
||||
|
||||
@ -105,36 +139,33 @@ void init_mapnode(IIrrlichtWrapper *irrlicht)
|
||||
}
|
||||
else
|
||||
{
|
||||
f->setAllTextures(irrlicht->getTextureId("leaves.png"));
|
||||
f->setAllTextures("[noalpha:leaves.png");
|
||||
}
|
||||
/*{
|
||||
TileSpec t;
|
||||
t.spec = TextureSpec(irrlicht->getTextureId("leaves.png"));
|
||||
//t.material_type = MATERIAL_ALPHA_SIMPLE;
|
||||
//t.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
f->setAllTiles(t);
|
||||
}*/
|
||||
|
||||
i = CONTENT_COALSTONE;
|
||||
f = &g_content_features[i];
|
||||
//f->translate_to = new MapNode(CONTENT_STONE, MINERAL_COAL);
|
||||
f->setAllTextures(TextureSpec(irrlicht->getTextureId("coal.png"),
|
||||
irrlicht->getTextureId("mineral_coal.png")));
|
||||
/*f->setAllTextures(TextureSpec(irrlicht->getTextureId("coal.png"),
|
||||
irrlicht->getTextureId("mineral_coal.png")));*/
|
||||
f->setAllTextures("stone.png^mineral_coal.png");
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_WOOD;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures(irrlicht->getTextureId("wood.png"));
|
||||
//f->setAllTextures(irrlicht->getTextureId("wood.png"));
|
||||
f->setAllTextures("wood.png");
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_MESE;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures(irrlicht->getTextureId("mese.png"));
|
||||
//f->setAllTextures(irrlicht->getTextureId("mese.png"));
|
||||
f->setAllTextures("mese.png");
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_CLOUD;
|
||||
f = &g_content_features[i];
|
||||
f->setAllTextures(irrlicht->getTextureId("cloud.png"));
|
||||
//f->setAllTextures(irrlicht->getTextureId("cloud.png"));
|
||||
f->setAllTextures("cloud.png");
|
||||
f->is_ground_content = true;
|
||||
|
||||
i = CONTENT_AIR;
|
||||
@ -150,7 +181,7 @@ void init_mapnode(IIrrlichtWrapper *irrlicht)
|
||||
|
||||
i = CONTENT_WATER;
|
||||
f = &g_content_features[i];
|
||||
f->setInventoryTexture(irrlicht->getTextureId("water.png"));
|
||||
//f->setInventoryTexture(irrlicht->getTextureId("water.png"));
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->solidness = 0; // Drawn separately, makes no faces
|
||||
@ -162,21 +193,23 @@ void init_mapnode(IIrrlichtWrapper *irrlicht)
|
||||
|
||||
i = CONTENT_WATERSOURCE;
|
||||
f = &g_content_features[i];
|
||||
f->setInventoryTexture(irrlicht->getTextureId("water.png"));
|
||||
//f->setInventoryTexture(irrlicht->getTextureId("water.png"));
|
||||
if(new_style_water)
|
||||
{
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
}
|
||||
else // old style
|
||||
{
|
||||
f->setAllTextures(irrlicht->getTextureId("water.png"), WATER_ALPHA);
|
||||
f->solidness = 1;
|
||||
|
||||
TileSpec t;
|
||||
t.spec = TextureSpec(irrlicht->getTextureId("water.png"));
|
||||
if(g_texturesource)
|
||||
t.texture = g_texturesource->getTexture("water.png");
|
||||
|
||||
t.alpha = WATER_ALPHA;
|
||||
t.material_type = MATERIAL_ALPHA_VERTEX;
|
||||
t.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
f->setAllTiles(t);
|
||||
f->solidness = 1;
|
||||
}
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
@ -188,7 +221,6 @@ void init_mapnode(IIrrlichtWrapper *irrlicht)
|
||||
|
||||
i = CONTENT_TORCH;
|
||||
f = &g_content_features[i];
|
||||
f->setInventoryTexture(irrlicht->getTextureId("torch_on_floor.png"));
|
||||
f->param_type = CPT_LIGHT;
|
||||
f->light_propagates = true;
|
||||
f->solidness = 0; // drawn separately, makes no faces
|
||||
@ -224,13 +256,23 @@ TileSpec MapNode::getTile(v3s16 dir)
|
||||
else
|
||||
spec = content_features(d).tiles[dir_i];
|
||||
|
||||
if(content_features(d).param_type == CPT_MINERAL)
|
||||
/*
|
||||
If it contains some mineral, change texture id
|
||||
*/
|
||||
if(content_features(d).param_type == CPT_MINERAL && g_texturesource)
|
||||
{
|
||||
u8 mineral = param & 0x1f;
|
||||
// Add mineral block texture
|
||||
textureid_t tid = mineral_block_texture(mineral);
|
||||
if(tid != 0)
|
||||
spec.spec.addTid(tid);
|
||||
std::string mineral_texture_name = mineral_block_texture(mineral);
|
||||
if(mineral_texture_name != "")
|
||||
{
|
||||
u32 orig_id = spec.texture.id;
|
||||
std::string texture_name = g_texturesource->getTextureName(orig_id);
|
||||
//texture_name += "^blit:";
|
||||
texture_name += "^";
|
||||
texture_name += mineral_texture_name;
|
||||
u32 new_id = g_texturesource->getTextureId(texture_name);
|
||||
spec.texture = g_texturesource->getTexture(new_id);
|
||||
}
|
||||
}
|
||||
|
||||
return spec;
|
||||
|
@ -132,9 +132,11 @@ struct ContentFeatures
|
||||
5: front
|
||||
*/
|
||||
TileSpec tiles[6];
|
||||
|
||||
|
||||
// TODO: Somehow specify inventory image
|
||||
//std::string inventory_image_path;
|
||||
TextureSpec inventory_texture;
|
||||
//TextureSpec inventory_texture;
|
||||
//u32 inventory_texture_id;
|
||||
|
||||
bool is_ground_content; //TODO: Remove, use walkable instead
|
||||
bool light_propagates;
|
||||
@ -167,27 +169,36 @@ struct ContentFeatures
|
||||
|
||||
~ContentFeatures();
|
||||
|
||||
// Quickhands for simple materials
|
||||
void setTexture(u16 i, const TextureSpec &spec, u8 alpha=255)
|
||||
/*
|
||||
Quickhands for simple materials
|
||||
*/
|
||||
|
||||
void setTexture(u16 i, std::string name, u8 alpha=255);
|
||||
|
||||
void setAllTextures(std::string name, u8 alpha=255)
|
||||
{
|
||||
tiles[i].spec = spec;
|
||||
for(u16 i=0; i<6; i++)
|
||||
{
|
||||
setTexture(i, name, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
/*void setTexture(u16 i, AtlasPointer p, u8 alpha=255)
|
||||
{
|
||||
tiles[i].texture = p;
|
||||
if(alpha != 255)
|
||||
{
|
||||
tiles[i].alpha = alpha;
|
||||
tiles[i].material_type = MATERIAL_ALPHA_VERTEX;
|
||||
}
|
||||
}
|
||||
void setAllTextures(const TextureSpec &spec, u8 alpha=255)
|
||||
void setAllTextures(AtlasPointer p, u8 alpha=255)
|
||||
{
|
||||
for(u16 i=0; i<6; i++)
|
||||
{
|
||||
setTexture(i, spec, alpha);
|
||||
setTexture(i, p, alpha);
|
||||
}
|
||||
|
||||
// Set this too so it can be left as is most times
|
||||
if(inventory_texture.empty())
|
||||
inventory_texture = spec;
|
||||
}
|
||||
}*/
|
||||
|
||||
void setTile(u16 i, const TileSpec &tile)
|
||||
{
|
||||
@ -201,10 +212,10 @@ struct ContentFeatures
|
||||
}
|
||||
}
|
||||
|
||||
void setInventoryTexture(const TextureSpec &spec)
|
||||
/*void setInventoryTexture(const TextureSpec &spec)
|
||||
{
|
||||
inventory_texture = spec;
|
||||
}
|
||||
}*/
|
||||
|
||||
/*void setInventoryImage(std::string imgname)
|
||||
{
|
||||
|
@ -27,7 +27,8 @@ const char *mineral_filenames[MINERAL_COUNT] =
|
||||
"mineral_iron.png"
|
||||
};
|
||||
|
||||
textureid_t mineral_textures[MINERAL_COUNT] = {0};
|
||||
//textureid_t mineral_textures[MINERAL_COUNT] = {0};
|
||||
std::string mineral_textures[MINERAL_COUNT];
|
||||
|
||||
void init_mineral(IIrrlichtWrapper *irrlicht)
|
||||
{
|
||||
@ -35,14 +36,17 @@ void init_mineral(IIrrlichtWrapper *irrlicht)
|
||||
{
|
||||
if(mineral_filenames[i] == NULL)
|
||||
continue;
|
||||
mineral_textures[i] = irrlicht->getTextureId(mineral_filenames[i]);
|
||||
//mineral_textures[i] = irrlicht->getTextureId(mineral_filenames[i]);
|
||||
//mineral_textures[i] = 0;
|
||||
mineral_textures[i] = mineral_filenames[i];
|
||||
}
|
||||
}
|
||||
|
||||
textureid_t mineral_block_texture(u8 mineral)
|
||||
//textureid_t mineral_block_texture(u8 mineral)
|
||||
std::string mineral_block_texture(u8 mineral)
|
||||
{
|
||||
if(mineral >= MINERAL_COUNT)
|
||||
return 0;
|
||||
return "";
|
||||
|
||||
return mineral_textures[mineral];
|
||||
}
|
||||
|
@ -40,7 +40,8 @@ void init_mineral(IIrrlichtWrapper *irrlicht);
|
||||
|
||||
#define MINERAL_COUNT 3
|
||||
|
||||
textureid_t mineral_block_texture(u8 mineral);
|
||||
//textureid_t mineral_block_texture(u8 mineral);
|
||||
std::string mineral_block_texture(u8 mineral);
|
||||
|
||||
inline CraftItem * getDiggedMineralItem(u8 mineral)
|
||||
{
|
||||
|
@ -1642,6 +1642,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
os<<name<<L",";
|
||||
}
|
||||
os<<L"}";
|
||||
if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
|
||||
os<<" WARNING: Map saving is disabled."<<std::endl;
|
||||
// Send message
|
||||
SendChatMessage(peer_id, os.str());
|
||||
}
|
||||
|
@ -20,6 +20,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#ifndef TEXTURE_HEADER
|
||||
#define TEXTURE_HEADER
|
||||
|
||||
// This file now contains all that was here
|
||||
#include "tile.h"
|
||||
|
||||
// TODO: Remove this
|
||||
typedef u16 textureid_t;
|
||||
|
||||
#if 0
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
//#include "utility.h"
|
||||
#include "debug.h"
|
||||
@ -122,3 +130,5 @@ struct TextureSpec
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
770
src/tile.cpp
770
src/tile.cpp
@ -18,10 +18,770 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
*/
|
||||
|
||||
#include "tile.h"
|
||||
//#include "porting.h"
|
||||
// For IrrlichtWrapper
|
||||
//#include "main.h"
|
||||
//#include <string>
|
||||
#include "debug.h"
|
||||
|
||||
// Nothing here
|
||||
TextureSource::TextureSource(IrrlichtDevice *device):
|
||||
m_device(device),
|
||||
m_main_atlas_image(NULL),
|
||||
m_main_atlas_texture(NULL)
|
||||
{
|
||||
assert(m_device);
|
||||
|
||||
m_atlaspointer_cache_mutex.Init();
|
||||
|
||||
m_main_thread = get_current_thread_id();
|
||||
|
||||
// Add a NULL AtlasPointer as the first index, named ""
|
||||
m_atlaspointer_cache.push_back(SourceAtlasPointer(""));
|
||||
m_name_to_id[""] = 0;
|
||||
|
||||
// Build main texture atlas
|
||||
buildMainAtlas();
|
||||
}
|
||||
|
||||
TextureSource::~TextureSource()
|
||||
{
|
||||
}
|
||||
|
||||
void TextureSource::processQueue()
|
||||
{
|
||||
/*
|
||||
Fetch textures
|
||||
*/
|
||||
if(m_get_texture_queue.size() > 0)
|
||||
{
|
||||
GetRequest<std::string, u32, u8, u8>
|
||||
request = m_get_texture_queue.pop();
|
||||
|
||||
dstream<<"INFO: TextureSource::processQueue(): "
|
||||
<<"got texture request with "
|
||||
<<"name="<<request.key
|
||||
<<std::endl;
|
||||
|
||||
GetResult<std::string, u32, u8, u8>
|
||||
result;
|
||||
result.key = request.key;
|
||||
result.callers = request.callers;
|
||||
result.item = getTextureIdDirect(request.key);
|
||||
|
||||
request.dest->push_back(result);
|
||||
}
|
||||
}
|
||||
|
||||
u32 TextureSource::getTextureId(const std::string &name)
|
||||
{
|
||||
//dstream<<"INFO: getTextureId(): name="<<name<<std::endl;
|
||||
|
||||
{
|
||||
/*
|
||||
See if texture already exists
|
||||
*/
|
||||
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
|
||||
core::map<std::string, u32>::Node *n;
|
||||
n = m_name_to_id.find(name);
|
||||
if(n != NULL)
|
||||
{
|
||||
return n->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Get texture
|
||||
*/
|
||||
if(get_current_thread_id() == m_main_thread)
|
||||
{
|
||||
return getTextureIdDirect(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
dstream<<"INFO: getTextureId(): Queued: name="<<name<<std::endl;
|
||||
|
||||
// We're gonna ask the result to be put into here
|
||||
ResultQueue<std::string, u32, u8, u8> result_queue;
|
||||
|
||||
// Throw a request in
|
||||
m_get_texture_queue.add(name, 0, 0, &result_queue);
|
||||
|
||||
dstream<<"INFO: Waiting for texture from main thread, name="
|
||||
<<name<<std::endl;
|
||||
|
||||
try
|
||||
{
|
||||
// Wait result for a second
|
||||
GetResult<std::string, u32, u8, u8>
|
||||
result = result_queue.pop_front(1000);
|
||||
|
||||
// Check that at least something worked OK
|
||||
assert(result.key == name);
|
||||
|
||||
return result.item;
|
||||
}
|
||||
catch(ItemNotFoundException &e)
|
||||
{
|
||||
dstream<<"WARNING: Waiting for texture timed out."<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dstream<<"WARNING: getTextureId(): Failed"<<std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Draw a progress bar on the image
|
||||
void make_progressbar(float value, video::IImage *image);
|
||||
|
||||
/*
|
||||
Generate image based on a string like "stone.png" or "[crack0".
|
||||
if baseimg is NULL, it is created. Otherwise stuff is made on it.
|
||||
*/
|
||||
bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
video::IVideoDriver* driver);
|
||||
|
||||
/*
|
||||
Generates an image from a full string like
|
||||
"stone.png^mineral_coal.png^[crack0".
|
||||
|
||||
This is used by buildMainAtlas().
|
||||
*/
|
||||
video::IImage* generate_image_from_scratch(std::string name,
|
||||
video::IVideoDriver* driver);
|
||||
|
||||
/*
|
||||
This method generates all the textures
|
||||
*/
|
||||
u32 TextureSource::getTextureIdDirect(const std::string &name)
|
||||
{
|
||||
dstream<<"INFO: getTextureIdDirect(): name="<<name<<std::endl;
|
||||
|
||||
// Empty name means texture 0
|
||||
if(name == "")
|
||||
{
|
||||
dstream<<"INFO: getTextureIdDirect(): name is empty"<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Calling only allowed from main thread
|
||||
*/
|
||||
if(get_current_thread_id() != m_main_thread)
|
||||
{
|
||||
dstream<<"ERROR: TextureSource::getTextureIdDirect() "
|
||||
"called not from main thread"<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
See if texture already exists
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
|
||||
|
||||
core::map<std::string, u32>::Node *n;
|
||||
n = m_name_to_id.find(name);
|
||||
if(n != NULL)
|
||||
{
|
||||
dstream<<"INFO: getTextureIdDirect(): name="<<name
|
||||
<<" found in cache"<<std::endl;
|
||||
return n->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
dstream<<"INFO: getTextureIdDirect(): name="<<name
|
||||
<<" NOT found in cache. Creating it."<<std::endl;
|
||||
|
||||
/*
|
||||
Get the base image
|
||||
*/
|
||||
|
||||
char separator = '^';
|
||||
|
||||
/*
|
||||
This is set to the id of the base image.
|
||||
If left 0, there is no base image and a completely new image
|
||||
is made.
|
||||
*/
|
||||
u32 base_image_id = 0;
|
||||
|
||||
// Find last meta separator in name
|
||||
s32 last_separator_position = -1;
|
||||
for(s32 i=name.size()-1; i>=0; i--)
|
||||
{
|
||||
if(name[i] == separator)
|
||||
{
|
||||
last_separator_position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
If separator was found, construct the base name and make the
|
||||
base image using a recursive call
|
||||
*/
|
||||
std::string base_image_name;
|
||||
if(last_separator_position != -1)
|
||||
{
|
||||
// Construct base name
|
||||
base_image_name = name.substr(0, last_separator_position);
|
||||
dstream<<"INFO: getTextureIdDirect(): Calling itself recursively"
|
||||
" to get base image, name="<<base_image_name<<std::endl;
|
||||
base_image_id = getTextureIdDirect(base_image_name);
|
||||
}
|
||||
|
||||
dstream<<"base_image_id="<<base_image_id<<std::endl;
|
||||
|
||||
video::IVideoDriver* driver = m_device->getVideoDriver();
|
||||
assert(driver);
|
||||
|
||||
video::ITexture *t = NULL;
|
||||
|
||||
/*
|
||||
An image will be built from files and then converted into a texture.
|
||||
*/
|
||||
video::IImage *baseimg = NULL;
|
||||
|
||||
// If a base image was found, copy it to baseimg
|
||||
if(base_image_id != 0)
|
||||
{
|
||||
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
|
||||
|
||||
SourceAtlasPointer ap = m_atlaspointer_cache[base_image_id];
|
||||
|
||||
video::IImage *image = ap.atlas_img;
|
||||
|
||||
core::dimension2d<u32> dim = ap.intsize;
|
||||
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
|
||||
core::position2d<s32> pos_to(0,0);
|
||||
core::position2d<s32> pos_from = ap.intpos;
|
||||
|
||||
image->copyTo(
|
||||
baseimg, // target
|
||||
v2s32(0,0), // position in target
|
||||
core::rect<s32>(pos_from, dim) // from
|
||||
);
|
||||
|
||||
dstream<<"INFO: getTextureIdDirect(): Loaded \""
|
||||
<<base_image_name<<"\" from image cache"
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
/*
|
||||
Parse out the last part of the name of the image and act
|
||||
according to it
|
||||
*/
|
||||
|
||||
std::string last_part_of_name = name.substr(last_separator_position+1);
|
||||
dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
|
||||
|
||||
// Generate image according to part of name
|
||||
if(generate_image(last_part_of_name, baseimg, driver) == false)
|
||||
{
|
||||
dstream<<"INFO: getTextureIdDirect(): "
|
||||
"failed to generate \""<<last_part_of_name<<"\""
|
||||
<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If no resulting image, return NULL
|
||||
if(baseimg == NULL)
|
||||
{
|
||||
dstream<<"WARNING: getTextureIdDirect(): baseimg is NULL (attempted to"
|
||||
" create texture \""<<name<<"\""<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create texture from resulting image
|
||||
t = driver->addTexture(name.c_str(), baseimg);
|
||||
|
||||
// If no texture
|
||||
if(t == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
Add texture to caches
|
||||
*/
|
||||
|
||||
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
|
||||
|
||||
u32 id = m_atlaspointer_cache.size();
|
||||
AtlasPointer ap(id);
|
||||
ap.atlas = t;
|
||||
ap.pos = v2f(0,0);
|
||||
ap.size = v2f(1,1);
|
||||
ap.tiled = 0;
|
||||
SourceAtlasPointer nap(name, ap, baseimg, v2s32(0,0), baseimg->getDimension());
|
||||
m_atlaspointer_cache.push_back(nap);
|
||||
m_name_to_id.insert(name, id);
|
||||
|
||||
dstream<<"INFO: getTextureIdDirect(): name="<<name
|
||||
<<": succesfully returning id="<<id<<std::endl;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string TextureSource::getTextureName(u32 id)
|
||||
{
|
||||
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
|
||||
|
||||
if(id >= m_atlaspointer_cache.size())
|
||||
{
|
||||
dstream<<"WARNING: TextureSource::getTextureName(): id="<<id
|
||||
<<" >= m_atlaspointer_cache.size()="
|
||||
<<m_atlaspointer_cache.size()<<std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
return m_atlaspointer_cache[id].name;
|
||||
}
|
||||
|
||||
|
||||
AtlasPointer TextureSource::getTexture(u32 id)
|
||||
{
|
||||
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
|
||||
|
||||
if(id >= m_atlaspointer_cache.size())
|
||||
return AtlasPointer(0, NULL);
|
||||
|
||||
return m_atlaspointer_cache[id].a;
|
||||
}
|
||||
|
||||
void TextureSource::buildMainAtlas()
|
||||
{
|
||||
dstream<<"TextureSource::buildMainAtlas()"<<std::endl;
|
||||
|
||||
//return; // Disable (for testing)
|
||||
|
||||
video::IVideoDriver* driver = m_device->getVideoDriver();
|
||||
assert(driver);
|
||||
|
||||
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
|
||||
|
||||
// Create an image of the right size
|
||||
core::dimension2d<u32> atlas_dim(1024,1024);
|
||||
video::IImage *atlas_img =
|
||||
driver->createImage(video::ECF_A8R8G8B8, atlas_dim);
|
||||
|
||||
/*
|
||||
A list of stuff to add. This should contain as much of the
|
||||
stuff shown in game as possible, to minimize texture changes.
|
||||
*/
|
||||
|
||||
core::array<std::string> sourcelist;
|
||||
|
||||
sourcelist.push_back("stone.png");
|
||||
sourcelist.push_back("mud.png");
|
||||
sourcelist.push_back("sand.png");
|
||||
sourcelist.push_back("grass.png");
|
||||
sourcelist.push_back("mud.png");
|
||||
sourcelist.push_back("tree.png");
|
||||
sourcelist.push_back("tree_top.png");
|
||||
sourcelist.push_back("water.png");
|
||||
sourcelist.push_back("leaves.png");
|
||||
sourcelist.push_back("mud.png^grass_side.png");
|
||||
|
||||
sourcelist.push_back("stone.png^mineral_coal.png");
|
||||
sourcelist.push_back("stone.png^mineral_iron.png");
|
||||
sourcelist.push_back("mud.png^mineral_coal.png");
|
||||
sourcelist.push_back("mud.png^mineral_iron.png");
|
||||
sourcelist.push_back("sand.png^mineral_coal.png");
|
||||
sourcelist.push_back("sand.png^mineral_iron.png");
|
||||
|
||||
/*
|
||||
First pass: generate almost everything
|
||||
*/
|
||||
core::position2d<s32> pos_in_atlas(0,0);
|
||||
for(u32 i=0; i<sourcelist.size(); i++)
|
||||
{
|
||||
std::string name = sourcelist[i];
|
||||
|
||||
/*video::IImage *img = driver->createImageFromFile(
|
||||
porting::getDataPath(name.c_str()).c_str());
|
||||
if(img == NULL)
|
||||
continue;
|
||||
|
||||
core::dimension2d<u32> dim = img->getDimension();
|
||||
// Make a copy with the right color format
|
||||
video::IImage *img2 =
|
||||
driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
img->copyTo(img2);
|
||||
img->drop();*/
|
||||
|
||||
// Generate image by name
|
||||
video::IImage *img2 = generate_image_from_scratch(name, driver);
|
||||
core::dimension2d<u32> dim = img2->getDimension();
|
||||
|
||||
// Tile it a few times in the X direction
|
||||
u16 xwise_tiling = 16;
|
||||
for(u32 j=0; j<xwise_tiling; j++)
|
||||
{
|
||||
// Copy the copy to the atlas
|
||||
img2->copyToWithAlpha(atlas_img,
|
||||
pos_in_atlas + v2s32(j*dim.Width,0),
|
||||
core::rect<s32>(v2s32(0,0), dim),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);
|
||||
}
|
||||
|
||||
img2->drop();
|
||||
|
||||
/*
|
||||
Add texture to caches
|
||||
*/
|
||||
|
||||
// Get next id
|
||||
u32 id = m_atlaspointer_cache.size();
|
||||
|
||||
// Create AtlasPointer
|
||||
AtlasPointer ap(id);
|
||||
ap.atlas = NULL; // Set on the second pass
|
||||
ap.pos = v2f((float)pos_in_atlas.X/(float)atlas_dim.Width,
|
||||
(float)pos_in_atlas.Y/(float)atlas_dim.Height);
|
||||
ap.size = v2f((float)dim.Width/(float)atlas_dim.Width,
|
||||
(float)dim.Width/(float)atlas_dim.Height);
|
||||
ap.tiled = xwise_tiling;
|
||||
|
||||
// Create SourceAtlasPointer and add to containers
|
||||
SourceAtlasPointer nap(name, ap, atlas_img, pos_in_atlas, dim);
|
||||
m_atlaspointer_cache.push_back(nap);
|
||||
m_name_to_id.insert(name, id);
|
||||
|
||||
// Increment position
|
||||
pos_in_atlas.Y += dim.Height;
|
||||
}
|
||||
|
||||
/*
|
||||
Make texture
|
||||
*/
|
||||
video::ITexture *t = driver->addTexture("__main_atlas__", atlas_img);
|
||||
assert(t);
|
||||
|
||||
/*
|
||||
Second pass: set texture pointer in generated AtlasPointers
|
||||
*/
|
||||
for(u32 i=0; i<sourcelist.size(); i++)
|
||||
{
|
||||
std::string name = sourcelist[i];
|
||||
u32 id = m_name_to_id[name];
|
||||
m_atlaspointer_cache[id].a.atlas = t;
|
||||
}
|
||||
|
||||
/*
|
||||
Write image to file so that it can be inspected
|
||||
*/
|
||||
driver->writeImageToFile(atlas_img,
|
||||
porting::getDataPath("main_atlas.png").c_str());
|
||||
}
|
||||
|
||||
video::IImage* generate_image_from_scratch(std::string name,
|
||||
video::IVideoDriver* driver)
|
||||
{
|
||||
dstream<<"INFO: generate_image_from_scratch(): "
|
||||
"name="<<name<<std::endl;
|
||||
|
||||
/*
|
||||
Get the base image
|
||||
*/
|
||||
|
||||
video::IImage *baseimg = NULL;
|
||||
|
||||
char separator = '^';
|
||||
|
||||
// Find last meta separator in name
|
||||
s32 last_separator_position = -1;
|
||||
for(s32 i=name.size()-1; i>=0; i--)
|
||||
{
|
||||
if(name[i] == separator)
|
||||
{
|
||||
last_separator_position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*dstream<<"INFO: generate_image_from_scratch(): "
|
||||
<<"last_separator_position="<<last_separator_position
|
||||
<<std::endl;*/
|
||||
|
||||
/*
|
||||
If separator was found, construct the base name and make the
|
||||
base image using a recursive call
|
||||
*/
|
||||
std::string base_image_name;
|
||||
if(last_separator_position != -1)
|
||||
{
|
||||
// Construct base name
|
||||
base_image_name = name.substr(0, last_separator_position);
|
||||
dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
|
||||
" to get base image, name="<<base_image_name<<std::endl;
|
||||
baseimg = generate_image_from_scratch(base_image_name, driver);
|
||||
}
|
||||
|
||||
/*
|
||||
Parse out the last part of the name of the image and act
|
||||
according to it
|
||||
*/
|
||||
|
||||
std::string last_part_of_name = name.substr(last_separator_position+1);
|
||||
dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
|
||||
|
||||
// Generate image according to part of name
|
||||
if(generate_image(last_part_of_name, baseimg, driver) == false)
|
||||
{
|
||||
dstream<<"INFO: generate_image_from_scratch(): "
|
||||
"failed to generate \""<<last_part_of_name<<"\""
|
||||
<<std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return baseimg;
|
||||
}
|
||||
|
||||
bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
video::IVideoDriver* driver)
|
||||
{
|
||||
// Stuff starting with [ are special commands
|
||||
if(part_of_name[0] != '[')
|
||||
{
|
||||
// A normal texture; load it from a file
|
||||
std::string path = porting::getDataPath(part_of_name.c_str());
|
||||
dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
|
||||
<<"\""<<std::endl;
|
||||
|
||||
video::IImage *image = driver->createImageFromFile(path.c_str());
|
||||
|
||||
if(image == NULL)
|
||||
{
|
||||
dstream<<"WARNING: Could not load image \""<<part_of_name
|
||||
<<"\" from path \""<<path<<"\""
|
||||
<<" while building texture"<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If base image is NULL, load as base.
|
||||
if(baseimg == NULL)
|
||||
{
|
||||
dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
|
||||
/*
|
||||
Copy it this way to get an alpha channel.
|
||||
Otherwise images with alpha cannot be blitted on
|
||||
images that don't have alpha in the original file.
|
||||
*/
|
||||
core::dimension2d<u32> dim = image->getDimension();
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
image->copyTo(baseimg);
|
||||
image->drop();
|
||||
}
|
||||
// Else blit on base.
|
||||
else
|
||||
{
|
||||
dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
|
||||
// Size of the copied area
|
||||
core::dimension2d<u32> dim = image->getDimension();
|
||||
//core::dimension2d<u32> dim(16,16);
|
||||
// Position to copy the blitted to in the base image
|
||||
core::position2d<s32> pos_to(0,0);
|
||||
// Position to copy the blitted from in the blitted image
|
||||
core::position2d<s32> pos_from(0,0);
|
||||
// Blit
|
||||
image->copyToWithAlpha(baseimg, pos_to,
|
||||
core::rect<s32>(pos_from, dim),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);
|
||||
// Drop image
|
||||
image->drop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// A special texture modification
|
||||
|
||||
dstream<<"INFO: getTextureIdDirect(): generating special "
|
||||
<<"modification \""<<part_of_name<<"\""
|
||||
<<std::endl;
|
||||
|
||||
if(part_of_name.substr(0,6) == "[crack")
|
||||
{
|
||||
if(baseimg == NULL)
|
||||
{
|
||||
dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
|
||||
<<"for part_of_name="<<part_of_name
|
||||
<<", cancelling."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
u16 progression = stoi(part_of_name.substr(6));
|
||||
// Size of the base image
|
||||
core::dimension2d<u32> dim_base = baseimg->getDimension();
|
||||
// Crack will be drawn at this size
|
||||
u32 cracksize = 16;
|
||||
// Size of the crack image
|
||||
core::dimension2d<u32> dim_crack(cracksize,cracksize);
|
||||
// Position to copy the crack from in the crack image
|
||||
core::position2d<s32> pos_other(0, 16 * progression);
|
||||
|
||||
video::IImage *crackimage = driver->createImageFromFile(
|
||||
porting::getDataPath("crack.png").c_str());
|
||||
|
||||
if(crackimage)
|
||||
{
|
||||
/*crackimage->copyToWithAlpha(baseimg, v2s32(0,0),
|
||||
core::rect<s32>(pos_other, dim_base),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);*/
|
||||
|
||||
for(u32 y0=0; y0<dim_base.Height/dim_crack.Height; y0++)
|
||||
for(u32 x0=0; x0<dim_base.Width/dim_crack.Width; x0++)
|
||||
{
|
||||
// Position to copy the crack to in the base image
|
||||
core::position2d<s32> pos_base(x0*cracksize, y0*cracksize);
|
||||
crackimage->copyToWithAlpha(baseimg, pos_base,
|
||||
core::rect<s32>(pos_other, dim_crack),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);
|
||||
}
|
||||
|
||||
crackimage->drop();
|
||||
}
|
||||
}
|
||||
else if(part_of_name.substr(0,8) == "[combine")
|
||||
{
|
||||
// "[combine:16x128:0,0=stone.png:0,16=grass.png"
|
||||
Strfnd sf(part_of_name);
|
||||
sf.next(":");
|
||||
u32 w0 = stoi(sf.next("x"));
|
||||
u32 h0 = stoi(sf.next(":"));
|
||||
dstream<<"INFO: combined w="<<w0<<" h="<<h0<<std::endl;
|
||||
core::dimension2d<u32> dim(w0,h0);
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
while(sf.atend() == false)
|
||||
{
|
||||
u32 x = stoi(sf.next(","));
|
||||
u32 y = stoi(sf.next("="));
|
||||
std::string filename = sf.next(":");
|
||||
dstream<<"INFO: Adding \""<<filename
|
||||
<<"\" to combined ("<<x<<","<<y<<")"
|
||||
<<std::endl;
|
||||
video::IImage *img = driver->createImageFromFile(
|
||||
porting::getDataPath(filename.c_str()).c_str());
|
||||
if(img)
|
||||
{
|
||||
core::dimension2d<u32> dim = img->getDimension();
|
||||
dstream<<"INFO: Size "<<dim.Width
|
||||
<<"x"<<dim.Height<<std::endl;
|
||||
core::position2d<s32> pos_base(x, y);
|
||||
video::IImage *img2 =
|
||||
driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
img->copyTo(img2);
|
||||
img->drop();
|
||||
img2->copyToWithAlpha(baseimg, pos_base,
|
||||
core::rect<s32>(v2s32(0,0), dim),
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);
|
||||
img2->drop();
|
||||
}
|
||||
else
|
||||
{
|
||||
dstream<<"WARNING: img==NULL"<<std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(part_of_name.substr(0,12) == "[progressbar")
|
||||
{
|
||||
if(baseimg == NULL)
|
||||
{
|
||||
dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
|
||||
<<"for part_of_name="<<part_of_name
|
||||
<<", cancelling."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
float value = stof(part_of_name.substr(12));
|
||||
make_progressbar(value, baseimg);
|
||||
}
|
||||
// "[noalpha:filename.png"
|
||||
// Use an image without it's alpha channel
|
||||
else if(part_of_name.substr(0,8) == "[noalpha")
|
||||
{
|
||||
if(baseimg != NULL)
|
||||
{
|
||||
dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
|
||||
<<"for part_of_name="<<part_of_name
|
||||
<<", cancelling."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string filename = part_of_name.substr(9);
|
||||
|
||||
std::string path = porting::getDataPath(filename.c_str());
|
||||
|
||||
dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
|
||||
<<"\""<<std::endl;
|
||||
|
||||
video::IImage *image = driver->createImageFromFile(path.c_str());
|
||||
|
||||
if(image == NULL)
|
||||
{
|
||||
dstream<<"WARNING: getTextureIdDirect(): Loading path \""
|
||||
<<path<<"\" failed"<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
core::dimension2d<u32> dim = image->getDimension();
|
||||
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
|
||||
|
||||
// Set alpha to full
|
||||
for(u32 y=0; y<dim.Height; y++)
|
||||
for(u32 x=0; x<dim.Width; x++)
|
||||
{
|
||||
video::SColor c = image->getPixel(x,y);
|
||||
c.setAlpha(255);
|
||||
image->setPixel(x,y,c);
|
||||
}
|
||||
// Blit
|
||||
image->copyTo(baseimg);
|
||||
|
||||
image->drop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dstream<<"WARNING: getTextureIdDirect(): Invalid "
|
||||
" modification: \""<<part_of_name<<"\""<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void make_progressbar(float value, video::IImage *image)
|
||||
{
|
||||
if(image == NULL)
|
||||
return;
|
||||
|
||||
core::dimension2d<u32> size = image->getDimension();
|
||||
|
||||
u32 barheight = 1;
|
||||
u32 barpad_x = 1;
|
||||
u32 barpad_y = 1;
|
||||
u32 barwidth = size.Width - barpad_x*2;
|
||||
v2u32 barpos(barpad_x, size.Height - barheight - barpad_y);
|
||||
|
||||
u32 barvalue_i = (u32)(((float)barwidth * value) + 0.5);
|
||||
|
||||
video::SColor active(255,255,0,0);
|
||||
video::SColor inactive(255,0,0,0);
|
||||
for(u32 x0=0; x0<barwidth; x0++)
|
||||
{
|
||||
video::SColor *c;
|
||||
if(x0 < barvalue_i)
|
||||
c = &active;
|
||||
else
|
||||
c = &inactive;
|
||||
u32 x = x0 + barpos.X;
|
||||
for(u32 y=barpos.Y; y<barpos.Y+barheight; y++)
|
||||
{
|
||||
image->setPixel(x,y, *c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
219
src/tile.h
219
src/tile.h
@ -21,10 +21,208 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#define TILE_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
//#include "utility.h"
|
||||
#include "texture.h"
|
||||
#include "threads.h"
|
||||
#include "utility.h"
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
Specifies a texture in an atlas.
|
||||
|
||||
This is used to specify single textures also.
|
||||
|
||||
This has been designed to be small enough to be thrown around a lot.
|
||||
*/
|
||||
struct AtlasPointer
|
||||
{
|
||||
u32 id; // Texture id
|
||||
video::ITexture *atlas; // Atlas in where the texture is
|
||||
v2f pos; // Position in atlas
|
||||
v2f size; // Size in atlas
|
||||
u16 tiled; // X-wise tiling count. If 0, width of atlas is width of image.
|
||||
|
||||
AtlasPointer(
|
||||
u16 id_,
|
||||
video::ITexture *atlas_=NULL,
|
||||
v2f pos_=v2f(0,0),
|
||||
v2f size_=v2f(1,1),
|
||||
u16 tiled_=1
|
||||
):
|
||||
id(id_),
|
||||
atlas(atlas_),
|
||||
pos(pos_),
|
||||
size(size_),
|
||||
tiled(tiled_)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const AtlasPointer &other)
|
||||
{
|
||||
return (
|
||||
id == other.id
|
||||
);
|
||||
/*return (
|
||||
id == other.id &&
|
||||
atlas == other.atlas &&
|
||||
pos == other.pos &&
|
||||
size == other.size &&
|
||||
tiled == other.tiled
|
||||
);*/
|
||||
}
|
||||
|
||||
float x0(){ return pos.X; }
|
||||
float x1(){ return pos.X + size.X; }
|
||||
float y0(){ return pos.Y; }
|
||||
float y1(){ return pos.Y + size.Y; }
|
||||
};
|
||||
|
||||
/*
|
||||
An internal variant of the former with more data.
|
||||
*/
|
||||
struct SourceAtlasPointer
|
||||
{
|
||||
std::string name;
|
||||
AtlasPointer a;
|
||||
video::IImage *atlas_img; // The source image of the atlas
|
||||
// Integer variants of position and size
|
||||
v2s32 intpos;
|
||||
v2u32 intsize;
|
||||
|
||||
SourceAtlasPointer(
|
||||
const std::string &name_,
|
||||
AtlasPointer a_=AtlasPointer(0, NULL),
|
||||
video::IImage *atlas_img_=NULL,
|
||||
v2s32 intpos_=v2s32(0,0),
|
||||
v2u32 intsize_=v2u32(0,0)
|
||||
):
|
||||
name(name_),
|
||||
a(a_),
|
||||
atlas_img(atlas_img_),
|
||||
intpos(intpos_),
|
||||
intsize(intsize_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Creates and caches textures.
|
||||
*/
|
||||
class TextureSource
|
||||
{
|
||||
public:
|
||||
TextureSource(IrrlichtDevice *device);
|
||||
~TextureSource();
|
||||
|
||||
/*
|
||||
Processes queued texture requests from other threads.
|
||||
|
||||
Shall be called from the main thread.
|
||||
*/
|
||||
void processQueue();
|
||||
|
||||
/*
|
||||
Example case:
|
||||
Now, assume a texture with the id 1 exists, and has the name
|
||||
"stone.png^mineral1".
|
||||
Then a random thread calls getTextureId for a texture called
|
||||
"stone.png^mineral1^crack0".
|
||||
...Now, WTF should happen? Well:
|
||||
- getTextureId strips off stuff recursively from the end until
|
||||
the remaining part is found, or nothing is left when
|
||||
something is stripped out
|
||||
|
||||
But it is slow to search for textures by names and modify them
|
||||
like that?
|
||||
- ContentFeatures is made to contain ids for the basic plain
|
||||
textures
|
||||
- Crack textures can be slow by themselves, but the framework
|
||||
must be fast.
|
||||
|
||||
Example case #2:
|
||||
- Assume a texture with the id 1 exists, and has the name
|
||||
"stone.png^mineral1" and is specified as a part of some atlas.
|
||||
- Now MapBlock::getNodeTile() stumbles upon a node which uses
|
||||
texture id 1, and finds out that NODEMOD_CRACK must be applied
|
||||
with progression=0
|
||||
- It finds out the name of the texture with getTextureName(1),
|
||||
appends "^crack0" to it and gets a new texture id with
|
||||
getTextureId("stone.png^mineral1^crack0")
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Gets a texture id from cache or
|
||||
- if main thread, from getTextureIdDirect
|
||||
- if other thread, adds to request queue and waits for main thread
|
||||
*/
|
||||
u32 getTextureId(const std::string &name);
|
||||
|
||||
/*
|
||||
Example names:
|
||||
"stone.png"
|
||||
"stone.png^crack2"
|
||||
"stone.png^blit:mineral_coal.png"
|
||||
"stone.png^blit:mineral_coal.png^crack1"
|
||||
|
||||
- If texture specified by name is found from cache, return the
|
||||
cached id.
|
||||
- Otherwise generate the texture, add to cache and return id.
|
||||
Recursion is used to find out the largest found part of the
|
||||
texture and continue based on it.
|
||||
|
||||
The id 0 points to a NULL texture. It is returned in case of error.
|
||||
*/
|
||||
u32 getTextureIdDirect(const std::string &name);
|
||||
|
||||
/*
|
||||
Finds out the name of a cached texture.
|
||||
*/
|
||||
std::string getTextureName(u32 id);
|
||||
|
||||
/*
|
||||
If texture specified by the name pointed by the id doesn't
|
||||
exist, create it, then return the cached texture.
|
||||
|
||||
Can be called from any thread. If called from some other thread
|
||||
and not found in cache, the call is queued to the main thread
|
||||
for processing.
|
||||
*/
|
||||
AtlasPointer getTexture(u32 id);
|
||||
|
||||
AtlasPointer getTexture(const std::string &name)
|
||||
{
|
||||
return getTexture(getTextureId(name));
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
Build the main texture atlas which contains most of the
|
||||
textures.
|
||||
|
||||
This is called by the constructor.
|
||||
*/
|
||||
void buildMainAtlas();
|
||||
|
||||
// The id of the thread that is allowed to use irrlicht directly
|
||||
threadid_t m_main_thread;
|
||||
// The irrlicht device
|
||||
IrrlichtDevice *m_device;
|
||||
|
||||
// A texture id is index in this array.
|
||||
// The first position contains a NULL texture.
|
||||
core::array<SourceAtlasPointer> m_atlaspointer_cache;
|
||||
// Maps a texture name to an index in the former.
|
||||
core::map<std::string, u32> m_name_to_id;
|
||||
// The two former containers are behind this mutex
|
||||
JMutex m_atlaspointer_cache_mutex;
|
||||
|
||||
// Main texture atlas. This is filled at startup and is then not touched.
|
||||
video::IImage *m_main_atlas_image;
|
||||
video::ITexture *m_main_atlas_texture;
|
||||
|
||||
// Queued texture fetches (to be processed by the main thread)
|
||||
RequestQueue<std::string, u32, u8, u8> m_get_texture_queue;
|
||||
};
|
||||
|
||||
enum MaterialType{
|
||||
MATERIAL_ALPHA_NONE,
|
||||
MATERIAL_ALPHA_VERTEX,
|
||||
@ -38,12 +236,17 @@ enum MaterialType{
|
||||
/*
|
||||
This fully defines the looks of a tile.
|
||||
The SMaterial of a tile is constructed according to this.
|
||||
|
||||
TODO: Change this to use an AtlasPointer
|
||||
*/
|
||||
struct TileSpec
|
||||
{
|
||||
TileSpec():
|
||||
texture(0),
|
||||
alpha(255),
|
||||
material_type(MATERIAL_ALPHA_NONE),
|
||||
// Use this so that leaves don't need a separate material
|
||||
//material_type(MATERIAL_ALPHA_SIMPLE),
|
||||
material_flags(
|
||||
MATERIAL_FLAG_BACKFACE_CULLING
|
||||
)
|
||||
@ -53,7 +256,7 @@ struct TileSpec
|
||||
bool operator==(TileSpec &other)
|
||||
{
|
||||
return (
|
||||
spec == other.spec &&
|
||||
texture == other.texture &&
|
||||
alpha == other.alpha &&
|
||||
material_type == other.material_type &&
|
||||
material_flags == other.material_flags
|
||||
@ -80,8 +283,14 @@ struct TileSpec
|
||||
material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING) ? true : false;
|
||||
}
|
||||
|
||||
// Specification of texture
|
||||
TextureSpec spec;
|
||||
// NOTE: Deprecated, i guess?
|
||||
void setTexturePos(u8 tx_, u8 ty_, u8 tw_, u8 th_)
|
||||
{
|
||||
texture.pos = v2f((float)tx_/256.0, (float)ty_/256.0);
|
||||
texture.size = v2f(((float)tw_ + 1.0)/256.0, ((float)th_ + 1.0)/256.0);
|
||||
}
|
||||
|
||||
AtlasPointer texture;
|
||||
// Vertex alpha
|
||||
u8 alpha;
|
||||
// Material type
|
||||
|
Loading…
Reference in New Issue
Block a user