Skip to content

Commit

Permalink
Move palette creation to TextureSource
Browse files Browse the repository at this point in the history
  • Loading branch information
juhdanad authored and sofar committed Apr 9, 2017
1 parent b27e8e4 commit c444628
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 88 deletions.
69 changes: 67 additions & 2 deletions src/client/tile.cpp
Expand Up @@ -341,6 +341,8 @@ class TextureSource : public IWritableTextureSource
*/
video::ITexture* getTextureForMesh(const std::string &name, u32 *id);

virtual Palette* getPalette(const std::string &name);

// Returns a pointer to the irrlicht device
virtual IrrlichtDevice* getDevice()
{
Expand Down Expand Up @@ -377,8 +379,6 @@ class TextureSource : public IWritableTextureSource
video::ITexture* generateTextureFromMesh(
const TextureFromMeshParams &params);

video::IImage* generateImage(const std::string &name);

video::ITexture* getNormalTexture(const std::string &name);
video::SColor getTextureAverageColor(const std::string &name);
video::ITexture *getShaderFlagsTexture(bool normamap_present);
Expand All @@ -401,6 +401,13 @@ class TextureSource : public IWritableTextureSource
// if baseimg is NULL, it is created. Otherwise stuff is made on it.
bool generateImagePart(std::string part_of_name, video::IImage *& baseimg);

/*! Generates an image from a full string like
* "stone.png^mineral_coal.png^[crack:1:0".
* Shall be called from the main thread.
* The returned Image should be dropped.
*/
video::IImage* generateImage(const std::string &name);

// Thread-safe cache of what source images are known (true = known)
MutexedMap<std::string, bool> m_source_image_existence;

Expand All @@ -419,6 +426,9 @@ class TextureSource : public IWritableTextureSource
// but can't be deleted because the ITexture* might still be used
std::vector<video::ITexture*> m_texture_trash;

// Maps image file names to loaded palettes.
UNORDERED_MAP<std::string, Palette> m_palettes;

// Cached settings needed for making textures from meshes
bool m_setting_trilinear_filter;
bool m_setting_bilinear_filter;
Expand Down Expand Up @@ -682,6 +692,61 @@ video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *
return getTexture(name + "^[applyfiltersformesh", id);
}

Palette* TextureSource::getPalette(const std::string &name)
{
// Only the main thread may load images
sanity_check(thr_is_current_thread(m_main_thread));

if (name == "")
return NULL;

UNORDERED_MAP<std::string, Palette>::iterator it = m_palettes.find(name);
if (it == m_palettes.end()) {
// Create palette
video::IImage *img = generateImage(name);
if (!img) {
warningstream << "TextureSource::getPalette(): palette \"" << name
<< "\" could not be loaded." << std::endl;
return NULL;
}
Palette new_palette;
u32 w = img->getDimension().Width;
u32 h = img->getDimension().Height;
// Real area of the image
u32 area = h * w;
if (area == 0)
return NULL;
if (area > 256) {
warningstream << "TextureSource::getPalette(): the specified"
<< " palette image \"" << name << "\" is larger than 256"
<< " pixels, using the first 256." << std::endl;
area = 256;
} else if (256 % area != 0)
warningstream << "TextureSource::getPalette(): the "
<< "specified palette image \"" << name << "\" does not "
<< "contain power of two pixels." << std::endl;
// We stretch the palette so it will fit 256 values
// This many param2 values will have the same color
u32 step = 256 / area;
// For each pixel in the image
for (u32 i = 0; i < area; i++) {
video::SColor c = img->getPixel(i % w, i / w);
// Fill in palette with 'step' colors
for (u32 j = 0; j < step; j++)
new_palette.push_back(c);
}
img->drop();
// Fill in remaining elements
while (new_palette.size() < 256)
new_palette.push_back(video::SColor(0xFFFFFFFF));
m_palettes[name] = new_palette;
it = m_palettes.find(name);
}
if (it != m_palettes.end())
return &((*it).second);
return NULL;
}

void TextureSource::processQueue()
{
/*
Expand Down
15 changes: 9 additions & 6 deletions src/client/tile.h
Expand Up @@ -33,6 +33,8 @@ class IGameDef;
struct TileSpec;
struct TileDef;

typedef std::vector<video::SColor> Palette;

/*
tile.{h,cpp}: Texture handling stuff.
*/
Expand Down Expand Up @@ -106,14 +108,15 @@ class ITextureSource : public ISimpleTextureSource
const std::string &name, u32 *id = NULL)=0;
virtual video::ITexture* getTextureForMesh(
const std::string &name, u32 *id = NULL) = 0;
/*!
* Returns a palette from the given texture name.
* The pointer is valid until the texture source is
* destructed.
* Should be called from the main thread.
*/
virtual Palette* getPalette(const std::string &name) = 0;
virtual IrrlichtDevice* getDevice()=0;
virtual bool isKnownSourceImage(const std::string &name)=0;
/*! Generates an image from a full string like
* "stone.png^mineral_coal.png^[crack:1:0".
* Shall be called from the main thread.
* The returned Image should be dropped.
*/
virtual video::IImage* generateImage(const std::string &name)=0;
virtual video::ITexture* generateTextureFromMesh(
const TextureFromMeshParams &params)=0;
virtual video::ITexture* getNormalTexture(const std::string &name)=0;
Expand Down
82 changes: 2 additions & 80 deletions src/nodedef.cpp
Expand Up @@ -786,6 +786,8 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
tiledef_special[j].backface_culling, material_type);
}

palette = tsrc->getPalette(palette_name);

if ((drawtype == NDT_MESH) && (mesh != "")) {
// Meshnode drawtype
// Read the mesh and apply scale
Expand Down Expand Up @@ -859,9 +861,6 @@ class CNodeDefManager: public IWritableNodeDefManager {
virtual void removeNode(const std::string &name);
virtual void updateAliases(IItemDefManager *idef);
virtual void applyTextureOverrides(const std::string &override_filepath);
//! Returns a palette or NULL if not found. Only on client.
std::vector<video::SColor> *getPalette(const ContentFeatures &f,
const IGameDef *gamedef);
virtual void updateTextures(IGameDef *gamedef,
void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
void *progress_cbk_args);
Expand Down Expand Up @@ -910,9 +909,6 @@ class CNodeDefManager: public IWritableNodeDefManager {
// Next possibly free id
content_t m_next_id;

// Maps image file names to loaded palettes.
UNORDERED_MAP<std::string, std::vector<video::SColor> > m_palettes;

// NodeResolvers to callback once node registration has ended
std::vector<NodeResolver *> m_pending_resolve_callbacks;

Expand Down Expand Up @@ -1401,78 +1397,6 @@ void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath
}
}

std::vector<video::SColor> *CNodeDefManager::getPalette(
const ContentFeatures &f, const IGameDef *gamedef)
{
#ifndef SERVER
// This works because colors always use the most significant bits
// of param2. If you add a new colored type which uses param2
// in a more advanced way, you should change this code, too.
u32 palette_pixels = 0;
switch (f.param_type_2) {
case CPT2_COLOR:
palette_pixels = 256;
break;
case CPT2_COLORED_FACEDIR:
palette_pixels = 8;
break;
case CPT2_COLORED_WALLMOUNTED:
palette_pixels = 32;
break;
default:
return NULL;
}
// This many param2 values will have the same color
u32 step = 256 / palette_pixels;
const std::string &name = f.palette_name;
if (name == "")
return NULL;
Client *client = (Client *) gamedef;
ITextureSource *tsrc = client->tsrc();

UNORDERED_MAP<std::string, std::vector<video::SColor> >::iterator it =
m_palettes.find(name);
if (it == m_palettes.end()) {
// Create palette
if (!tsrc->isKnownSourceImage(name)) {
warningstream << "CNodeDefManager::getPalette(): palette \"" << name
<< "\" could not be loaded." << std::endl;
return NULL;
}
video::IImage *img = tsrc->generateImage(name);
std::vector<video::SColor> new_palette;
u32 w = img->getDimension().Width;
u32 h = img->getDimension().Height;
// Real area of the image
u32 area = h * w;
if (area != palette_pixels)
warningstream << "CNodeDefManager::getPalette(): the "
<< "specified palette image \"" << name << "\" does not "
<< "contain exactly " << palette_pixels
<< " pixels." << std::endl;
if (area > palette_pixels)
area = palette_pixels;
// For each pixel in the image
for (u32 i = 0; i < area; i++) {
video::SColor c = img->getPixel(i % w, i / w);
// Fill in palette with 'step' colors
for (u32 j = 0; j < step; j++)
new_palette.push_back(c);
}
img->drop();
// Fill in remaining elements
while (new_palette.size() < 256)
new_palette.push_back(video::SColor(0xFFFFFFFF));
m_palettes[name] = new_palette;
it = m_palettes.find(name);
}
if (it != m_palettes.end())
return &((*it).second);

#endif
return NULL;
}

void CNodeDefManager::updateTextures(IGameDef *gamedef,
void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
void *progress_callback_args)
Expand All @@ -1489,12 +1413,10 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
TextureSettings tsettings;
tsettings.readSettings();

m_palettes.clear();
u32 size = m_content_features.size();

for (u32 i = 0; i < size; i++) {
ContentFeatures *f = &(m_content_features[i]);
f->palette = getPalette(*f, gamedef);
f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
progress_callback(progress_callback_args, i, size);
}
Expand Down

0 comments on commit c444628

Please sign in to comment.