Skip to content

Commit 96c34d3

Browse files
kahrlPilzAdam
authored andcommittedAug 4, 2013
Fix crack overlay for animated textures
1 parent 2336d21 commit 96c34d3

File tree

2 files changed

+145
-112
lines changed

2 files changed

+145
-112
lines changed
 

‎src/mapblock_mesh.cpp

+26-7
Original file line numberDiff line numberDiff line change
@@ -1133,12 +1133,17 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
11331133
if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
11341134
{
11351135
ITextureSource *tsrc = data->m_gamedef->tsrc();
1136-
std::string crack_basename = tsrc->getTextureName(p.tile.texture_id);
1136+
// Find the texture name plus ^[crack:N:
1137+
std::ostringstream os(std::ios::binary);
1138+
os<<tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
11371139
if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1138-
crack_basename += "^[cracko";
1139-
else
1140-
crack_basename += "^[crack";
1141-
m_crack_materials.insert(std::make_pair(i, crack_basename));
1140+
os<<"o"; // use ^[cracko
1141+
os<<":"<<(u32)p.tile.animation_frame_count<<":";
1142+
m_crack_materials.insert(std::make_pair(i, os.str()));
1143+
// Replace tile texture with the cracked one
1144+
p.tile.texture = tsrc->getTexture(
1145+
os.str()+"0",
1146+
&p.tile.texture_id);
11421147
}
11431148
// - Texture animation
11441149
if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
@@ -1313,8 +1318,22 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
13131318
ITextureSource *tsrc = m_gamedef->getTextureSource();
13141319
std::ostringstream os;
13151320
os<<basename<<crack;
1316-
buf->getMaterial().setTexture(0,
1317-
tsrc->getTexture(os.str()));
1321+
u32 new_texture_id = 0;
1322+
video::ITexture *new_texture =
1323+
tsrc->getTexture(os.str(), &new_texture_id);
1324+
buf->getMaterial().setTexture(0, new_texture);
1325+
1326+
// If the current material is also animated,
1327+
// update animation info
1328+
std::map<u32, TileSpec>::iterator anim_iter =
1329+
m_animation_tiles.find(i->first);
1330+
if(anim_iter != m_animation_tiles.end()){
1331+
TileSpec &tile = anim_iter->second;
1332+
tile.texture = new_texture;
1333+
tile.texture_id = new_texture_id;
1334+
// force animation update
1335+
m_animation_frames[i->first] = -1;
1336+
}
13181337
}
13191338

13201339
m_last_crack = crack;

‎src/tile.cpp

+119-105
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,11 @@ class TextureSource : public IWritableTextureSource
379379
const TextureFromMeshParams &params);
380380

381381
// Generates an image from a full string like
382-
// "stone.png^mineral_coal.png^[crack0".
382+
// "stone.png^mineral_coal.png^[crack:1:0".
383383
// Shall be called from the main thread.
384384
video::IImage* generateImageFromScratch(std::string name);
385385

386-
// Generate image based on a string like "stone.png" or "[crack0".
386+
// Generate image based on a string like "stone.png" or "[crack:1:0".
387387
// if baseimg is NULL, it is created. Otherwise stuff is made on it.
388388
// Shall be called from the main thread.
389389
bool generateImage(std::string part_of_name, video::IImage *& baseimg);
@@ -543,14 +543,21 @@ u32 TextureSource::getTextureId(const std::string &name)
543543
return 0;
544544
}
545545

546-
// Overlay image on top of another image (used for cracks)
547-
void overlay(video::IImage *image, video::IImage *overlay);
548-
549546
// Draw an image on top of an another one, using the alpha channel of the
550547
// source image
551548
static void blit_with_alpha(video::IImage *src, video::IImage *dst,
552549
v2s32 src_pos, v2s32 dst_pos, v2u32 size);
553550

551+
// Like blit_with_alpha, but only modifies destination pixels that
552+
// are fully opaque
553+
static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
554+
v2s32 src_pos, v2s32 dst_pos, v2u32 size);
555+
556+
// Draw or overlay a crack
557+
static void draw_crack(video::IImage *crack, video::IImage *dst,
558+
bool use_overlay, u32 frame_count, u32 progression,
559+
video::IVideoDriver *driver);
560+
554561
// Brighten image
555562
void brighten(video::IImage *image);
556563
// Parse a transform name
@@ -1032,8 +1039,10 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
10321039
<<std::endl;*/
10331040

10341041
/*
1035-
[crackN
1042+
[crack:N:P
1043+
[cracko:N:P
10361044
Adds a cracking texture
1045+
N = animation frame count, P = crack progression
10371046
*/
10381047
if(part_of_name.substr(0,6) == "[crack")
10391048
{
@@ -1044,24 +1053,14 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
10441053
<<"\", cancelling."<<std::endl;
10451054
return false;
10461055
}
1047-
1056+
10481057
// Crack image number and overlay option
1049-
s32 progression = 0;
1050-
bool use_overlay = false;
1051-
if(part_of_name.substr(6,1) == "o")
1052-
{
1053-
progression = stoi(part_of_name.substr(7));
1054-
use_overlay = true;
1055-
}
1056-
else
1057-
{
1058-
progression = stoi(part_of_name.substr(6));
1059-
use_overlay = false;
1060-
}
1058+
bool use_overlay = (part_of_name[6] == 'o');
1059+
Strfnd sf(part_of_name);
1060+
sf.next(":");
1061+
u32 frame_count = stoi(sf.next(":"));
1062+
u32 progression = stoi(sf.next(":"));
10611063

1062-
// Size of the base image
1063-
core::dimension2d<u32> dim_base = baseimg->getDimension();
1064-
10651064
/*
10661065
Load crack image.
10671066
@@ -1070,60 +1069,12 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
10701069
*/
10711070
video::IImage *img_crack = m_sourcecache.getOrLoad(
10721071
"crack_anylength.png", m_device);
1073-
1072+
10741073
if(img_crack && progression >= 0)
10751074
{
1076-
// Dimension of original image
1077-
core::dimension2d<u32> dim_crack
1078-
= img_crack->getDimension();
1079-
// Count of crack stages
1080-
s32 crack_count = dim_crack.Height / dim_crack.Width;
1081-
// Limit progression
1082-
if(progression > crack_count-1)
1083-
progression = crack_count-1;
1084-
// Dimension of a single crack stage
1085-
core::dimension2d<u32> dim_crack_cropped(
1086-
dim_crack.Width,
1087-
dim_crack.Width
1088-
);
1089-
// Create cropped and scaled crack images
1090-
video::IImage *img_crack_cropped = driver->createImage(
1091-
video::ECF_A8R8G8B8, dim_crack_cropped);
1092-
video::IImage *img_crack_scaled = driver->createImage(
1093-
video::ECF_A8R8G8B8, dim_base);
1094-
1095-
if(img_crack_cropped && img_crack_scaled)
1096-
{
1097-
// Crop crack image
1098-
v2s32 pos_crack(0, progression*dim_crack.Width);
1099-
img_crack->copyTo(img_crack_cropped,
1100-
v2s32(0,0),
1101-
core::rect<s32>(pos_crack, dim_crack_cropped));
1102-
// Scale crack image by copying
1103-
img_crack_cropped->copyToScaling(img_crack_scaled);
1104-
// Copy or overlay crack image
1105-
if(use_overlay)
1106-
{
1107-
overlay(baseimg, img_crack_scaled);
1108-
}
1109-
else
1110-
{
1111-
/*img_crack_scaled->copyToWithAlpha(
1112-
baseimg,
1113-
v2s32(0,0),
1114-
core::rect<s32>(v2s32(0,0), dim_base),
1115-
video::SColor(255,255,255,255));*/
1116-
blit_with_alpha(img_crack_scaled, baseimg,
1117-
v2s32(0,0), v2s32(0,0), dim_base);
1118-
}
1119-
}
1120-
1121-
if(img_crack_scaled)
1122-
img_crack_scaled->drop();
1123-
1124-
if(img_crack_cropped)
1125-
img_crack_cropped->drop();
1126-
1075+
draw_crack(img_crack, baseimg,
1076+
use_overlay, frame_count,
1077+
progression, driver);
11271078
img_crack->drop();
11281079
}
11291080
}
@@ -1499,37 +1450,6 @@ bool TextureSource::generateImage(std::string part_of_name, video::IImage *& bas
14991450
return true;
15001451
}
15011452

1502-
void overlay(video::IImage *image, video::IImage *overlay)
1503-
{
1504-
/*
1505-
Copy overlay to image, taking alpha into account.
1506-
Where image is transparent, don't copy from overlay.
1507-
Images sizes must be identical.
1508-
*/
1509-
if(image == NULL || overlay == NULL)
1510-
return;
1511-
1512-
core::dimension2d<u32> dim = image->getDimension();
1513-
core::dimension2d<u32> dim_overlay = overlay->getDimension();
1514-
assert(dim == dim_overlay);
1515-
1516-
for(u32 y=0; y<dim.Height; y++)
1517-
for(u32 x=0; x<dim.Width; x++)
1518-
{
1519-
video::SColor c1 = image->getPixel(x,y);
1520-
video::SColor c2 = overlay->getPixel(x,y);
1521-
u32 a1 = c1.getAlpha();
1522-
u32 a2 = c2.getAlpha();
1523-
if(a1 == 255 && a2 != 0)
1524-
{
1525-
c1.setRed((c1.getRed()*(255-a2) + c2.getRed()*a2)/255);
1526-
c1.setGreen((c1.getGreen()*(255-a2) + c2.getGreen()*a2)/255);
1527-
c1.setBlue((c1.getBlue()*(255-a2) + c2.getBlue()*a2)/255);
1528-
}
1529-
image->setPixel(x,y,c1);
1530-
}
1531-
}
1532-
15331453
/*
15341454
Draw an image on top of an another one, using the alpha channel of the
15351455
source image
@@ -1554,6 +1474,100 @@ static void blit_with_alpha(video::IImage *src, video::IImage *dst,
15541474
}
15551475
}
15561476

1477+
/*
1478+
Draw an image on top of an another one, using the alpha channel of the
1479+
source image; only modify fully opaque pixels in destinaion
1480+
*/
1481+
static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
1482+
v2s32 src_pos, v2s32 dst_pos, v2u32 size)
1483+
{
1484+
for(u32 y0=0; y0<size.Y; y0++)
1485+
for(u32 x0=0; x0<size.X; x0++)
1486+
{
1487+
s32 src_x = src_pos.X + x0;
1488+
s32 src_y = src_pos.Y + y0;
1489+
s32 dst_x = dst_pos.X + x0;
1490+
s32 dst_y = dst_pos.Y + y0;
1491+
video::SColor src_c = src->getPixel(src_x, src_y);
1492+
video::SColor dst_c = dst->getPixel(dst_x, dst_y);
1493+
if(dst_c.getAlpha() == 255 && src_c.getAlpha() != 0)
1494+
{
1495+
dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f);
1496+
dst->setPixel(dst_x, dst_y, dst_c);
1497+
}
1498+
}
1499+
}
1500+
1501+
static void draw_crack(video::IImage *crack, video::IImage *dst,
1502+
bool use_overlay, u32 frame_count, u32 progression,
1503+
video::IVideoDriver *driver)
1504+
{
1505+
// Dimension of destination image
1506+
core::dimension2d<u32> dim_dst = dst->getDimension();
1507+
// Dimension of original image
1508+
core::dimension2d<u32> dim_crack = crack->getDimension();
1509+
// Count of crack stages
1510+
u32 crack_count = dim_crack.Height / dim_crack.Width;
1511+
// Limit frame_count
1512+
if(frame_count > dim_dst.Height)
1513+
frame_count = dim_dst.Height;
1514+
if(frame_count == 0)
1515+
frame_count = 1;
1516+
// Limit progression
1517+
if(progression > crack_count-1)
1518+
progression = crack_count-1;
1519+
// Dimension of a single crack stage
1520+
core::dimension2d<u32> dim_crack_cropped(
1521+
dim_crack.Width,
1522+
dim_crack.Width
1523+
);
1524+
// Dimension of the scaled crack stage,
1525+
// which is the same as the dimension of a single destination frame
1526+
core::dimension2d<u32> dim_crack_scaled(
1527+
dim_dst.Width,
1528+
dim_dst.Height / frame_count
1529+
);
1530+
// Create cropped and scaled crack images
1531+
video::IImage *crack_cropped = driver->createImage(
1532+
video::ECF_A8R8G8B8, dim_crack_cropped);
1533+
video::IImage *crack_scaled = driver->createImage(
1534+
video::ECF_A8R8G8B8, dim_crack_scaled);
1535+
1536+
if(crack_cropped && crack_scaled)
1537+
{
1538+
// Crop crack image
1539+
v2s32 pos_crack(0, progression*dim_crack.Width);
1540+
crack->copyTo(crack_cropped,
1541+
v2s32(0,0),
1542+
core::rect<s32>(pos_crack, dim_crack_cropped));
1543+
// Scale crack image by copying
1544+
crack_cropped->copyToScaling(crack_scaled);
1545+
// Copy or overlay crack image onto each frame
1546+
for(u32 i = 0; i < frame_count; ++i)
1547+
{
1548+
v2s32 dst_pos(0, dim_crack_scaled.Height * i);
1549+
if(use_overlay)
1550+
{
1551+
blit_with_alpha_overlay(crack_scaled, dst,
1552+
v2s32(0,0), dst_pos,
1553+
dim_crack_scaled);
1554+
}
1555+
else
1556+
{
1557+
blit_with_alpha(crack_scaled, dst,
1558+
v2s32(0,0), dst_pos,
1559+
dim_crack_scaled);
1560+
}
1561+
}
1562+
}
1563+
1564+
if(crack_scaled)
1565+
crack_scaled->drop();
1566+
1567+
if(crack_cropped)
1568+
crack_cropped->drop();
1569+
}
1570+
15571571
void brighten(video::IImage *image)
15581572
{
15591573
if(image == NULL)

0 commit comments

Comments
 (0)
Please sign in to comment.