add support for writting text on nodes - add text to signs

This commit is contained in:
darkrose 2015-01-23 00:11:59 +10:00
parent 1d5a1993bb
commit 56f8114d1c
12 changed files with 353 additions and 79 deletions

View File

@ -3624,9 +3624,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
};
TileSpec tiles[6];
NodeMetadata *meta = data->m_env->getMap().getNodeMetadata(p+blockpos_nodes);
for (int i = 0; i < 6; i++) {
// Handles facedir rotation for textures
tiles[i] = getNodeTile(n,p,tile_dirs[i],data->m_temp_mods);
tiles[i] = getNodeTile(n,p,tile_dirs[i],data->m_temp_mods,meta);
}
video::SColor c[8];
getLights(blockpos_nodes+p,c,data,smooth_lighting);
@ -3660,7 +3661,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
makeRotatedCuboid(&collector, pos, box.m_box, tiles, 6, c, txc, box.m_angle);
}
if (content_features(n).draw_type == CDT_NODEBOX_META) {
NodeMetadata *meta = data->m_env->getMap().getNodeMetadata(p+blockpos_nodes);
if (meta == NULL)
break;
boxes = meta->getNodeBoxes(n);

View File

@ -1046,6 +1046,7 @@ void content_mapnode_special(bool repeat)
f->pressure_type = CST_CRUSHABLE;
f->suffocation_per_second = 0;
content_nodebox_sign_wall(f);
f->setFaceText(5,FaceText(0.05,0.3,0.95,0.7));
i = CONTENT_SIGN;
f = &content_features(i);
@ -1072,6 +1073,7 @@ void content_mapnode_special(bool repeat)
f->pressure_type = CST_CRUSHABLE;
f->suffocation_per_second = 0;
content_nodebox_sign(f);
f->setFaceText(5,FaceText(0.05,0.0675,0.95,0.55));
f->setInventoryTextureNodeBox(i,"sign.png", "sign_front.png", "sign.png");
crafting::setSignRecipe(CONTENT_CRAFTITEM_WOOD_PLANK,CONTENT_SIGN);
crafting::setSignRecipe(CONTENT_CRAFTITEM_PINE_PLANK,CONTENT_SIGN);
@ -1104,6 +1106,7 @@ void content_mapnode_special(bool repeat)
f->pressure_type = CST_CRUSHABLE;
f->suffocation_per_second = 0;
content_nodebox_sign_ud(f);
f->setFaceText(5,FaceText(0.05,0.45,0.95,0.8875));
f->setInventoryTextureNodeBox(i,"sign.png", "sign_front.png", "sign.png");
i = CONTENT_LOCKABLE_SIGN_WALL;
@ -1133,6 +1136,8 @@ void content_mapnode_special(bool repeat)
f->pressure_type = CST_CRUSHABLE;
f->suffocation_per_second = 0;
content_nodebox_sign_wall(f);
f->setFaceText(4,FaceText(0.05,0.3,0.95,0.7,FTT_OWNER));
f->setFaceText(5,FaceText(0.05,0.3,0.95,0.7));
i = CONTENT_LOCKABLE_SIGN;
f = &content_features(i);
@ -1159,6 +1164,8 @@ void content_mapnode_special(bool repeat)
f->pressure_type = CST_CRUSHABLE;
f->suffocation_per_second = 0;
content_nodebox_sign(f);
f->setFaceText(4,FaceText(0.05,0.0675,0.95,0.55,FTT_OWNER));
f->setFaceText(5,FaceText(0.05,0.0675,0.95,0.55));
f->setInventoryTextureNodeBox(i,"sign.png", "sign_lock.png", "sign.png");
crafting::set1Any2Recipe(CONTENT_SIGN,CONTENT_CRAFTITEM_STEEL_INGOT,CONTENT_LOCKABLE_SIGN);
lists::add("craftguide",i);
@ -1189,6 +1196,8 @@ void content_mapnode_special(bool repeat)
f->pressure_type = CST_CRUSHABLE;
f->suffocation_per_second = 0;
content_nodebox_sign_ud(f);
f->setFaceText(4,FaceText(0.05,0.45,0.95,0.8875,FTT_OWNER));
f->setFaceText(5,FaceText(0.05,0.45,0.95,0.8875));
f->setInventoryTextureNodeBox(i,"sign.png", "sign_lock.png", "sign.png");
i = CONTENT_CHEST;

View File

@ -64,13 +64,16 @@ void SignNodeMetadata::serializeBody(std::ostream &os)
{
os<<serializeString(m_text);
}
std::wstring SignNodeMetadata::infoText()
{
return narrow_to_wide(std::string("\"")+m_text+"\"");
}
std::string SignNodeMetadata::getDrawSpecString()
{
return std::string("field[text;;") + m_text + "]";
std::string spec("size[5,2.5]");
spec += "field[0.75,0;4,1.5;text;;";
spec += m_text;
spec += "]";
spec += "button_exit[1.25,2;3,1;save;";
spec += gettext("Save");
spec += "]";
return spec;
}
bool SignNodeMetadata::import(NodeMetadata *meta)
{
@ -115,7 +118,7 @@ void LockingSignNodeMetadata::serializeBody(std::ostream &os)
}
std::wstring LockingSignNodeMetadata::infoText()
{
return narrow_to_wide(std::string("(")+m_owner+") \""+m_text+"\"");
return narrow_to_wide(std::string("(")+m_owner+")");
}
bool LockingSignNodeMetadata::receiveFields(std::string formname, std::map<std::string, std::string> fields, Player *player)
{
@ -126,7 +129,14 @@ bool LockingSignNodeMetadata::receiveFields(std::string formname, std::map<std::
}
std::string LockingSignNodeMetadata::getDrawSpecString()
{
return std::string("field[text;;") + m_text + "]";
std::string spec("size[5,2.5]");
spec += "field[0.75,0;4,1.5;text;;";
spec += m_text;
spec += "]";
spec += "button_exit[1.25,2;3,1;save;";
spec += gettext("Save");
spec += "]";
return spec;
}
bool LockingSignNodeMetadata::import(NodeMetadata *meta)
{

View File

@ -42,9 +42,8 @@ public:
static NodeMetadata* create(std::istream &is);
virtual NodeMetadata* clone();
virtual void serializeBody(std::ostream &os);
virtual std::wstring infoText();
std::string getText(){ return m_text; }
virtual std::string getText(){ return m_text; }
void setText(std::string t){ m_text = t; }
virtual bool receiveFields(std::string formname, std::map<std::string, std::string> fields, Player *player)
{
@ -76,7 +75,7 @@ public:
virtual std::string getInventoryOwner(){ return m_owner; }
virtual void setInventoryOwner(std::string t){ m_owner = t; }
std::string getText(){ return m_text; }
virtual std::string getText(){ return m_text; }
void setText(std::string t){ m_text = t; }
virtual bool receiveFields(std::string formname, std::map<std::string, std::string> fields, Player *player);
virtual std::string getDrawSpecString();

View File

@ -29,6 +29,7 @@
#include "map.h"
#include "main.h" // For g_settings and g_texturesource
#include "content_mapblock.h"
#include "content_nodemeta.h"
#include "settings.h"
#include "profiler.h"
#include "mesh.h"
@ -244,8 +245,7 @@ void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
Gets node tile from any place relative to block.
Returns TILE_NODE if doesn't exist or should not be drawn.
*/
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
NodeModMap &temp_mods)
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, NodeModMap &temp_mods, NodeMetadata *meta)
{
TileSpec spec;
spec = mn.getTile(face_dir);
@ -290,6 +290,47 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
}
}
if (meta) {
printf("meta!\n");
FaceText ft = mn.getFaceText(face_dir);
if (ft.m_hastext) {
printf("facetext!\n");
// 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<<orig_name<<"^[text:";
os<<ft.m_pos.UpperLeftCorner.X;
os<<",";
os<<ft.m_pos.UpperLeftCorner.Y;
os<<",";
os<<ft.m_pos.LowerRightCorner.X;
os<<",";
os<<ft.m_pos.LowerRightCorner.Y;
os<<",";
switch (ft.m_type) {
case FTT_BOOKCONTENT:
os<<((BookNodeMetadata*)meta)->getContent();
break;
case FTT_OWNER:
os<<meta->getOwner();
break;
case FTT_INVOWNER:
os<<meta->getInventoryOwner();
break;
default:
os<<meta->getText();
break;
}
// Get new texture
u32 new_id = g_texturesource->getTextureId(os.str());
spec.texture = g_texturesource->getTexture(new_id);
}
}
return spec;
}

View File

@ -112,7 +112,7 @@ private:
// Helper functions
video::SColor MapBlock_LightColor(u8 alpha, u8 light, bool selected=false);
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, NodeModMap &temp_mods);
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, NodeModMap &temp_mods, NodeMetadata *meta = NULL);
TileSpec getMetaTile(MapNode mn, v3s16 p, v3s16 face_dir, NodeModMap &temp_mods);
u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio);
u8 getSmoothLight(v3s16 p, v3s16 corner, VoxelManipulator &vmanip, u32 daynight_ratio);

View File

@ -404,36 +404,37 @@ TileSpec MapNode::getTileFrom(v3s16 dir, TileSpec raw_spec[6])
{
TileSpec spec;
s32 dir_i = 0;
ContentFeatures &f = content_features(*this);
if (
content_features(*this).param2_type == CPT_FACEDIR_SIMPLE
|| content_features(*this).param2_type == CPT_FACEDIR_WALLMOUNT
f.param2_type == CPT_FACEDIR_SIMPLE
|| f.param2_type == CPT_FACEDIR_WALLMOUNT
) {
dir = facedir_rotate(param2&0x0F, dir);
}else if (
content_features(*this).param_type == CPT_FACEDIR_SIMPLE
|| content_features(*this).param_type == CPT_FACEDIR_WALLMOUNT
f.param_type == CPT_FACEDIR_SIMPLE
|| f.param_type == CPT_FACEDIR_WALLMOUNT
) {
dir = facedir_rotate(param1, dir);
}
if(dir == v3s16(0,-1,0))
if (dir == v3s16(0,-1,0)) {
dir_i = 1;
else if(dir == v3s16(1,0,0))
}else if(dir == v3s16(1,0,0)) {
dir_i = 2;
else if(dir == v3s16(-1,0,0))
}else if(dir == v3s16(-1,0,0)) {
dir_i = 3;
else if(dir == v3s16(0,0,1))
}else if(dir == v3s16(0,0,1)) {
dir_i = 4;
else if(dir == v3s16(0,0,-1))
}else if(dir == v3s16(0,0,-1)) {
dir_i = 5;
}
spec = raw_spec[dir_i];
/*
If it contains some mineral, change texture id
*/
if(content_features(*this).param_type == CPT_MINERAL && g_texturesource)
if(f.param_type == CPT_MINERAL && g_texturesource)
{
u8 mineral = getMineral();
std::string mineral_texture_name = mineral_features(mineral).texture;
@ -448,11 +449,11 @@ TileSpec MapNode::getTileFrom(v3s16 dir, TileSpec raw_spec[6])
spec.texture = g_texturesource->getTexture(new_id);
}
}
if (content_features(*this).rotate_tile_with_nodebox) {
if (f.rotate_tile_with_nodebox) {
u8 facedir = 0;
if (content_features(*this).param_type == CPT_FACEDIR_SIMPLE) {
if (f.param_type == CPT_FACEDIR_SIMPLE) {
facedir = param1;
}else if (content_features(*this).param2_type == CPT_FACEDIR_SIMPLE) {
}else if (f.param2_type == CPT_FACEDIR_SIMPLE) {
facedir = (param2&0x0F);
}
if (dir_i == 0) {
@ -489,6 +490,35 @@ TileSpec MapNode::getTileFrom(v3s16 dir, TileSpec raw_spec[6])
return spec;
}
#endif
FaceText MapNode::getFaceText(v3s16 dir)
{
s32 dir_i = 0;
ContentFeatures &f = content_features(*this);
if (
f.param2_type == CPT_FACEDIR_SIMPLE
|| f.param2_type == CPT_FACEDIR_WALLMOUNT
) {
dir = facedir_rotate(param2&0x0F, dir);
}else if (
f.param_type == CPT_FACEDIR_SIMPLE
|| f.param_type == CPT_FACEDIR_WALLMOUNT
) {
dir = facedir_rotate(param1, dir);
}
if (dir == v3s16(0,-1,0)) {
dir_i = 1;
}else if(dir == v3s16(1,0,0)) {
dir_i = 2;
}else if(dir == v3s16(-1,0,0)) {
dir_i = 3;
}else if(dir == v3s16(0,0,1)) {
dir_i = 4;
}else if(dir == v3s16(0,0,-1)) {
dir_i = 5;
}
return f.facetexts[dir_i];
}
u8 MapNode::getMineral()
{

View File

@ -224,6 +224,44 @@ public:
aabb3f m_box;
};
enum FaceTextType {
FTT_INFO,
FTT_BOOKCONTENT,
FTT_OWNER,
FTT_INVOWNER
};
class FaceText
{
public:
FaceText():
m_hastext(false)
{
}
FaceText(f32 tlx, f32 tly, f32 brx, f32 bry):
m_type(FTT_INFO),
m_hastext(true)
{
#ifndef SERVER
m_pos = core::rect<f32>(tlx,tly,brx,bry);
#endif
}
FaceText(f32 tlx, f32 tly, f32 brx, f32 bry, FaceTextType type):
m_type(type),
m_hastext(true)
{
#ifndef SERVER
m_pos = core::rect<f32>(tlx,tly,brx,bry);
#endif
}
#ifndef SERVER
core::rect<f32> m_pos;
#endif
FaceTextType m_type;
bool m_hastext;
};
std::vector<NodeBox> transformNodeBox(MapNode &n,
const std::vector<NodeBox> &nodebox);
@ -255,6 +293,9 @@ struct ContentFeatures
std::vector<NodeBox> nodeboxes;
std::vector<NodeBox> wield_nodeboxes;
// positions for text on faces
FaceText facetexts[6];
// List of all block textures that have been used (value is dummy)
// Exists on server too for cleaner code in content_mapnode.cpp
core::map<std::string, bool> used_texturenames;
@ -393,6 +434,7 @@ struct ContentFeatures
0.5*BS
));
wield_nodeboxes.clear();
setAllFaceTexts(FaceText());
param_type = CPT_NONE;
param2_type = CPT_NONE;
draw_type = CDT_AIRLIKE;
@ -483,6 +525,18 @@ struct ContentFeatures
wield_nodeboxes.push_back(nb);
}
void setFaceText(u16 i, FaceText ft)
{
facetexts[i] = ft;
}
void setAllFaceTexts(FaceText ft)
{
for (u16 i=0; i<6; i++) {
setFaceText(i,ft);
}
}
/*
Quickhands for simple materials
*/
@ -907,6 +961,8 @@ struct MapNode
TileSpec getTileFrom(v3s16 dir, TileSpec raw_spec[6]);
#endif
FaceText getFaceText(v3s16 dir);
/*
Gets mineral content of node, if there is any.
MINERAL_NONE if doesn't contain or isn't able to contain mineral.

View File

@ -69,6 +69,7 @@ public:
virtual NodeMetadata* clone() = 0;
virtual void serializeBody(std::ostream &os) = 0;
virtual std::wstring infoText() {return L"";}
virtual std::string getText() {return "";}
virtual Inventory* getInventory() {return NULL;}
// This is called always after the inventory is modified, before
// the changes are copied elsewhere

View File

@ -31,53 +31,52 @@
std::string trim(const std::string &str);
class Strfnd{
std::string tek;
unsigned int p;
std::string tek;
unsigned int p;
public:
void start(std::string niinq){
tek = niinq;
p=0;
}
unsigned int where(){
return p;
}
void to(unsigned int i){
p = i;
}
std::string what(){
return tek;
}
std::string next(std::string plop){
//std::cout<<"tek=\""<<tek<<"\" plop=\""<<plop<<"\""<<std::endl;
size_t n;
std::string palautus;
if (p < tek.size())
{
//std::cout<<"\tp<tek.size()"<<std::endl;
if ((n = tek.find(plop, p)) == std::string::npos || plop == "")
{
//std::cout<<"\t\tn == string::npos || plop == \"\""<<std::endl;
n = tek.size();
}
else
{
//std::cout<<"\t\tn != string::npos"<<std::endl;
}
palautus = tek.substr(p, n-p);
p = n + plop.length();
}
//else
//std::cout<<"\tp>=tek.size()"<<std::endl;
//std::cout<<"palautus=\""<<palautus<<"\""<<std::endl;
return palautus;
}
bool atend(){
if(p>=tek.size()) return true;
return false;
}
Strfnd(std::string s){
start(s);
}
void start(std::string niinq)
{
tek = niinq;
p=0;
}
unsigned int where()
{
return p;
}
void to(unsigned int i)
{
p = i;
}
std::string what()
{
return tek;
}
std::string next(std::string plop)
{
size_t n;
std::string palautus;
if (p < tek.size()) {
if ((n = tek.find(plop, p)) == std::string::npos || plop == "")
n = tek.size();
palautus = tek.substr(p, n-p);
p = n + plop.length();
}
return palautus;
}
std::string end()
{
return tek.substr(p,tek.size()-p);
}
bool atend()
{
if (p>=tek.size())
return true;
return false;
}
Strfnd(std::string s)
{
start(s);
}
};
class WStrfnd{

View File

@ -26,12 +26,14 @@
#include "tile.h"
#include "debug.h"
#include "main.h" // for g_settings
#include "game.h"
#include "filesys.h"
#include "utility.h"
#include "settings.h"
#include "mesh.h"
#include "hex.h"
#include <ICameraSceneNode.h>
#include <IGUIStaticText.h>
#include "log.h"
#include "mapnode.h" // For texture atlas making
#include "mineral.h" // For texture atlas making
@ -218,11 +220,16 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
// 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;
size_t text_separator_position = name.find("^[text:");
if (text_separator_position == std::string::npos) {
for (s32 i=name.size()-1; i>=0; i--) {
if (name[i] == separator) {
last_separator_position = i;
break;
}
}
}else{
last_separator_position = text_separator_position;
}
/*
If separator was found, construct the base name and make the
@ -1670,6 +1677,127 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
blit_with_alpha_overlay(img, baseimg, v2s32(0,0), v2s32(0,0), dim);
img->drop();
}
/*
[text:x,y,X,Y,string
writes string to texture
*/
else if (part_of_name.substr(0,6) == "[text:") {
Strfnd sf(part_of_name);
sf.next(":");
std::string x = sf.next(",");
std::string y = sf.next(",");
std::string X = sf.next(",");
std::string Y = sf.next(",");
std::wstring text = narrow_to_wide(sf.end());
if (baseimg == NULL) {
errorstream << "generateImagePart(): baseimg != NULL "
<< "for part_of_name=\"" << part_of_name
<< "\", cancelling." << std::endl;
return false;
}
core::rect<f32> pos(
mystof(x.c_str()),
mystof(y.c_str()),
mystof(X.c_str()),
mystof(Y.c_str())
);
video::IVideoDriver *driver = device->getVideoDriver();
if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false) {
static bool warned = false;
if (!warned) {
errorstream<<"generateImagePart(): EVDF_RENDER_TO_TARGET not supported."<<std::endl;
warned = true;
}
return NULL;
}
core::dimension2d<u32> dim = baseimg->getDimension();
core::dimension2d<u32> rtt_dim(dim.Width*10,dim.Height*10);
std::string rtt_texture_name = part_of_name + "_RTT";
// Create render target texture
video::ITexture *rtt = driver->addRenderTargetTexture(rtt_dim, rtt_texture_name.c_str(), video::ECF_A8R8G8B8);
if (rtt == NULL) {
errorstream<<"generateImagePart(): addRenderTargetTexture"
" returned NULL."<<std::endl;
return NULL;
}
// Get the gui
gui::IGUIEnvironment *guienv = device->getGUIEnvironment();
assert(guienv);
gui::IGUISkin* skin = guienv->getSkin();
gui::IGUIFont *std_font = skin->getFont();
static gui::IGUIFont *tex_font = NULL;
#if USE_FREETYPE
tex_font = gui::CGUITTFont::createTTFont(guienv, getPath("font","liberationsans.ttf",false).c_str(),10);
#else
tex_font = guienv->getFont(getTexturePath("fontlucida.png").c_str());
#endif
if (tex_font)
skin->setFont(tex_font);
// Set render target
driver->setRenderTarget(rtt, false, true, video::SColor(0,0,0,0));
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
const core::rect<s32> rect(core::position2d<s32>(0,0),rtt_dim);
const core::rect<s32> srect(core::position2d<s32>(0,0),dim);
driver->beginScene(true, true, video::SColor(255,0,0,0));
video::ITexture *t = driver->addTexture(std::string(rtt_texture_name+"_BASE").c_str(), baseimg);
driver->draw2DImage(
t,
rect,
srect,
&rect,
colors,
true
);
const core::rect<s32> trect(
(f32)rtt_dim.Width*pos.UpperLeftCorner.X,
(f32)rtt_dim.Height*pos.UpperLeftCorner.Y,
(f32)rtt_dim.Width*pos.LowerRightCorner.X,
(f32)rtt_dim.Height*pos.LowerRightCorner.Y
);
gui::IGUIStaticText *e = guienv->addStaticText(text.c_str(), trect);
e->setTextAlignment(gui::EGUIA_CENTER,gui::EGUIA_CENTER);
// Render scene
e->draw();
//guienv->drawAll();
driver->endScene();
// remove that text so it doesn't appear in the game window for
// some insane irrlicht too many classes reason
e->remove();
// Unset render target
driver->setRenderTarget(0, false, true, 0);
skin->setFont(std_font);
// Create image of render target
video::IImage *image = driver->createImage(rtt, v2s32(0,0), rtt_dim);
assert(image);
video::IImage *new_baseimg = driver->createImage(video::ECF_A8R8G8B8, rtt_dim);
if (new_baseimg) {
baseimg->copyToScaling(new_baseimg);
baseimg->drop();
baseimg = new_baseimg;
}
if (image) {
image->copyTo(baseimg);
image->drop();
}
}
else
{
infostream<<"generate_image(): Invalid "

View File

@ -40,6 +40,7 @@ using namespace jthread;
u32 parseImageTransform(const std::string& s);
core::dimension2d<u32> imageTransformDimension(u32 transform, core::dimension2d<u32> dim);
void imageTransform(u32 transform, video::IImage *src, video::IImage *dst);
video::ITexture *addText(IrrlichtDevice *device, video::ITexture *tex, core::rect<f32> pos, std::wstring &s);
/*
Specifies a texture in an atlas.