redo collision, implement content draw type, rewrite mesh generator, implement nodeboxes, implement stairs and slabs

This commit is contained in:
darkrose 2013-07-27 02:06:22 +10:00
parent f61f0e2064
commit 3359eaf406
13 changed files with 1730 additions and 788 deletions

View File

@ -1,18 +1,18 @@
/*
Minetest-c55
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License along
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
@ -20,28 +20,257 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "collision.h"
#include "mapblock.h"
#include "map.h"
#include "log.h"
#include "main.h" // g_profiler
#include "profiler.h"
collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
const core::aabbox3d<f32> &box_0,
f32 dtime, v3f &pos_f, v3f &speed_f)
// Helper function:
// Checks for collision of a moving aabbox with a static aabbox
// Returns -1 if no collision, 0 if X collision, 1 if Y collision, 2 if Z collision
// The time after which the collision occurs is stored in dtime.
int axisAlignedCollision(
const aabb3f &staticbox, const aabb3f &movingbox,
const v3f &speed, f32 d, f32 &dtime)
{
//TimeTaker tt("axisAlignedCollision");
f32 xsize = (staticbox.MaxEdge.X - staticbox.MinEdge.X);
f32 ysize = (staticbox.MaxEdge.Y - staticbox.MinEdge.Y);
f32 zsize = (staticbox.MaxEdge.Z - staticbox.MinEdge.Z);
aabb3f relbox(
movingbox.MinEdge.X - staticbox.MinEdge.X,
movingbox.MinEdge.Y - staticbox.MinEdge.Y,
movingbox.MinEdge.Z - staticbox.MinEdge.Z,
movingbox.MaxEdge.X - staticbox.MinEdge.X,
movingbox.MaxEdge.Y - staticbox.MinEdge.Y,
movingbox.MaxEdge.Z - staticbox.MinEdge.Z
);
if(speed.X > 0) // Check for collision with X- plane
{
if(relbox.MaxEdge.X <= d)
{
dtime = - relbox.MaxEdge.X / speed.X;
if((relbox.MinEdge.Y + speed.Y * dtime < ysize) &&
(relbox.MaxEdge.Y + speed.Y * dtime > 0) &&
(relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
(relbox.MaxEdge.Z + speed.Z * dtime > 0))
return 0;
}
else if(relbox.MinEdge.X > xsize)
{
return -1;
}
}
else if(speed.X < 0) // Check for collision with X+ plane
{
if(relbox.MinEdge.X >= xsize - d)
{
dtime = (xsize - relbox.MinEdge.X) / speed.X;
if((relbox.MinEdge.Y + speed.Y * dtime < ysize) &&
(relbox.MaxEdge.Y + speed.Y * dtime > 0) &&
(relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
(relbox.MaxEdge.Z + speed.Z * dtime > 0))
return 0;
}
else if(relbox.MaxEdge.X < 0)
{
return -1;
}
}
// NO else if here
if(speed.Y > 0) // Check for collision with Y- plane
{
if(relbox.MaxEdge.Y <= d)
{
dtime = - relbox.MaxEdge.Y / speed.Y;
if((relbox.MinEdge.X + speed.X * dtime < xsize) &&
(relbox.MaxEdge.X + speed.X * dtime > 0) &&
(relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
(relbox.MaxEdge.Z + speed.Z * dtime > 0))
return 1;
}
else if(relbox.MinEdge.Y > ysize)
{
return -1;
}
}
else if(speed.Y < 0) // Check for collision with Y+ plane
{
if(relbox.MinEdge.Y >= ysize - d)
{
dtime = (ysize - relbox.MinEdge.Y) / speed.Y;
if((relbox.MinEdge.X + speed.X * dtime < xsize) &&
(relbox.MaxEdge.X + speed.X * dtime > 0) &&
(relbox.MinEdge.Z + speed.Z * dtime < zsize) &&
(relbox.MaxEdge.Z + speed.Z * dtime > 0))
return 1;
}
else if(relbox.MaxEdge.Y < 0)
{
return -1;
}
}
// NO else if here
if(speed.Z > 0) // Check for collision with Z- plane
{
if(relbox.MaxEdge.Z <= d)
{
dtime = - relbox.MaxEdge.Z / speed.Z;
if((relbox.MinEdge.X + speed.X * dtime < xsize) &&
(relbox.MaxEdge.X + speed.X * dtime > 0) &&
(relbox.MinEdge.Y + speed.Y * dtime < ysize) &&
(relbox.MaxEdge.Y + speed.Y * dtime > 0))
return 2;
}
//else if(relbox.MinEdge.Z > zsize)
//{
// return -1;
//}
}
else if(speed.Z < 0) // Check for collision with Z+ plane
{
if(relbox.MinEdge.Z >= zsize - d)
{
dtime = (zsize - relbox.MinEdge.Z) / speed.Z;
if((relbox.MinEdge.X + speed.X * dtime < xsize) &&
(relbox.MaxEdge.X + speed.X * dtime > 0) &&
(relbox.MinEdge.Y + speed.Y * dtime < ysize) &&
(relbox.MaxEdge.Y + speed.Y * dtime > 0))
return 2;
}
//else if(relbox.MaxEdge.Z < 0)
//{
// return -1;
//}
}
return -1;
}
// Helper function:
// Checks if moving the movingbox up by the given distance would hit a ceiling.
bool wouldCollideWithCeiling(
const std::vector<aabb3f> &staticboxes,
const aabb3f &movingbox,
f32 y_increase, f32 d)
{
//TimeTaker tt("wouldCollideWithCeiling");
assert(y_increase >= 0);
for(std::vector<aabb3f>::const_iterator
i = staticboxes.begin();
i != staticboxes.end(); i++)
{
const aabb3f& staticbox = *i;
if((movingbox.MaxEdge.Y - d <= staticbox.MinEdge.Y) &&
(movingbox.MaxEdge.Y + y_increase > staticbox.MinEdge.Y) &&
(movingbox.MinEdge.X < staticbox.MaxEdge.X) &&
(movingbox.MaxEdge.X > staticbox.MinEdge.X) &&
(movingbox.MinEdge.Z < staticbox.MaxEdge.Z) &&
(movingbox.MaxEdge.Z > staticbox.MinEdge.Z))
return true;
}
return false;
}
collisionMoveResult collisionMoveSimple(Map *map,
f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f)
{
//TimeTaker tt("collisionMoveSimple");
ScopeProfiler sp(g_profiler, "collisionMoveSimple avg", SPT_AVG);
collisionMoveResult result;
v3f oldpos_f = pos_f;
v3s16 oldpos_i = floatToInt(oldpos_f, BS);
/*
Calculate new velocity
*/
if( dtime > 0.5 ) {
infostream<<"collisionMoveSimple: WARNING: maximum step interval exceeded, lost movement details!"<<std::endl;
dtime = 0.5;
}
speed_f += accel_f * dtime;
// If there is no speed, there are no collisions
if(speed_f.getLength() == 0)
return result;
/*
Calculate new position
Collect node boxes in movement range
*/
pos_f += speed_f * dtime;
std::vector<aabb3f> cboxes;
std::vector<bool> is_unloaded;
std::vector<bool> is_step_up;
std::vector<v3s16> node_positions;
{
//TimeTaker tt2("collisionMoveSimple collect boxes");
ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);
v3s16 oldpos_i = floatToInt(pos_f, BS);
v3s16 newpos_i = floatToInt(pos_f + speed_f * dtime, BS);
s16 min_x = MYMIN(oldpos_i.X, newpos_i.X) + (box_0.MinEdge.X / BS) - 1;
s16 min_y = MYMIN(oldpos_i.Y, newpos_i.Y) + (box_0.MinEdge.Y / BS) - 1;
s16 min_z = MYMIN(oldpos_i.Z, newpos_i.Z) + (box_0.MinEdge.Z / BS) - 1;
s16 max_x = MYMAX(oldpos_i.X, newpos_i.X) + (box_0.MaxEdge.X / BS) + 1;
s16 max_y = MYMAX(oldpos_i.Y, newpos_i.Y) + (box_0.MaxEdge.Y / BS) + 1;
s16 max_z = MYMAX(oldpos_i.Z, newpos_i.Z) + (box_0.MaxEdge.Z / BS) + 1;
for(s16 x = min_x; x <= max_x; x++)
for(s16 y = min_y; y <= max_y; y++)
for(s16 z = min_z; z <= max_z; z++)
{
v3s16 p(x,y,z);
try{
// Object collides into walkable nodes
MapNode n = map->getNode(p);
const ContentFeatures &f = content_features(n);
if(f.walkable == false)
continue;
std::vector<aabb3f> nodeboxes = f.getNodeBoxes();
for(std::vector<aabb3f>::iterator
i = nodeboxes.begin();
i != nodeboxes.end(); i++)
{
aabb3f box = *i;
box.MinEdge += v3f(x, y, z)*BS;
box.MaxEdge += v3f(x, y, z)*BS;
cboxes.push_back(box);
is_unloaded.push_back(false);
is_step_up.push_back(false);
node_positions.push_back(p);
}
}
catch(InvalidPositionException &e)
{
// Collide with unloaded nodes
aabb3f box = getNodeBox(p, BS);
cboxes.push_back(box);
is_unloaded.push_back(true);
is_step_up.push_back(false);
node_positions.push_back(p);
}
}
} // tt2
assert(cboxes.size() == is_unloaded.size());
assert(cboxes.size() == is_step_up.size());
assert(cboxes.size() == node_positions.size());
/*
Collision detection
*/
// position in nodes
v3s16 pos_i = floatToInt(pos_f, BS);
/*
Collision uncertainty radius
Make it a bit larger than the maximum distance of movement
@ -53,57 +282,145 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
// This should always apply, otherwise there are glitches
assert(d > pos_max_d);
/*
Calculate collision box
*/
core::aabbox3d<f32> box = box_0;
box.MaxEdge += pos_f;
box.MinEdge += pos_f;
core::aabbox3d<f32> oldbox = box_0;
oldbox.MaxEdge += oldpos_f;
oldbox.MinEdge += oldpos_f;
int loopcount = 0;
/*
If the object lies on a walkable node, this is set to true.
*/
result.touching_ground = false;
try{
// Check for liquid, and damage = lava
MapNode n = map->getNode(pos_i);
if(content_features(n).liquid_type != LIQUID_NONE)
while(dtime > BS*1e-10)
{
result.in_liquid = true;
if (content_features(n).damage_per_second > 1.0)
result.touching_lethal = true;
}
}
catch(InvalidPositionException &e)
//TimeTaker tt3("collisionMoveSimple dtime loop");
ScopeProfiler sp(g_profiler, "collisionMoveSimple dtime loop avg", SPT_AVG);
// Avoid infinite loop
loopcount++;
if(loopcount >= 100)
{
// Doing nothing here will block the object from
// walking over map borders
infostream<<"collisionMoveSimple: WARNING: Loop count exceeded, aborting to avoid infiniite loop"<<std::endl;
dtime = 0;
break;
}
aabb3f movingbox = box_0;
movingbox.MinEdge += pos_f;
movingbox.MaxEdge += pos_f;
int nearest_collided = -1;
f32 nearest_dtime = dtime;
u32 nearest_boxindex = -1;
/*
Go through every node around the object
TODO: Calculate the range of nodes that need to be checked
Go through every nodebox, find nearest collision
*/
for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
for(u32 boxindex = 0; boxindex < cboxes.size(); boxindex++)
{
try{
// Object collides into walkable nodes
MapNode n = map->getNode(v3s16(x,y,z));
if(content_features(n).walkable == false)
// Ignore if already stepped up this nodebox.
if(is_step_up[boxindex])
continue;
}
catch(InvalidPositionException &e)
{
// Doing nothing here will block the object from
// walking over map borders
// Find nearest collision of the two boxes (raytracing-like)
f32 dtime_tmp;
int collided = axisAlignedCollision(
cboxes[boxindex], movingbox, speed_f, d, dtime_tmp);
if(collided == -1 || dtime_tmp >= nearest_dtime)
continue;
nearest_dtime = dtime_tmp;
nearest_collided = collided;
nearest_boxindex = boxindex;
}
core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
if(nearest_collided == -1)
{
// No collision with any collision box.
pos_f += speed_f * dtime;
dtime = 0; // Set to 0 to avoid "infinite" loop due to small FP numbers
}
else
{
// Otherwise, a collision occurred.
const aabb3f& cbox = cboxes[nearest_boxindex];
// Check for stairs.
bool step_up = (nearest_collided != 1) && // must not be Y direction
(movingbox.MinEdge.Y < cbox.MaxEdge.Y) &&
(movingbox.MinEdge.Y + stepheight > cbox.MaxEdge.Y) &&
(!wouldCollideWithCeiling(cboxes, movingbox,
cbox.MaxEdge.Y - movingbox.MinEdge.Y,
d));
// Move to the point of collision and reduce dtime by nearest_dtime
if(nearest_dtime < 0)
{
// Handle negative nearest_dtime (can be caused by the d allowance)
if(!step_up)
{
if(nearest_collided == 0)
pos_f.X += speed_f.X * nearest_dtime;
if(nearest_collided == 1)
pos_f.Y += speed_f.Y * nearest_dtime;
if(nearest_collided == 2)
pos_f.Z += speed_f.Z * nearest_dtime;
}
}
else
{
pos_f += speed_f * nearest_dtime;
dtime -= nearest_dtime;
}
bool is_collision = true;
if(is_unloaded[nearest_boxindex])
is_collision = false;
CollisionInfo info;
info.t = COLLISION_NODE;
info.node_p = node_positions[nearest_boxindex];
info.old_speed = speed_f;
// Set the speed component that caused the collision to zero
if(step_up)
{
// Special case: Handle stairs
is_step_up[nearest_boxindex] = true;
is_collision = false;
}
else if(nearest_collided == 0) // X
{
speed_f.X = 0;
result.collides = true;
result.collides_xz = true;
}
else if(nearest_collided == 1) // Y
{
speed_f.Y = 0;
result.collides = true;
}
else if(nearest_collided == 2) // Z
{
speed_f.Z = 0;
result.collides = true;
result.collides_xz = true;
}
info.new_speed = speed_f;
if(info.new_speed.getDistanceFrom(info.old_speed) < 0.1*BS)
is_collision = false;
if(is_collision){
result.collisions.push_back(info);
}
}
}
/*
Final touches: Check if standing on ground, step up stairs.
*/
aabb3f box = box_0;
box.MinEdge += pos_f;
box.MaxEdge += pos_f;
for(u32 boxindex = 0; boxindex < cboxes.size(); boxindex++)
{
const aabb3f& cbox = cboxes[boxindex];
/*
See if the object is touching ground.
@ -115,141 +432,26 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
Use 0.15*BS so that it is easier to get on a node.
*/
if(
//fabs(nodebox.MaxEdge.Y-box.MinEdge.Y) < d
fabs(nodebox.MaxEdge.Y-box.MinEdge.Y) < 0.15*BS
&& nodebox.MaxEdge.X-d > box.MinEdge.X
&& nodebox.MinEdge.X+d < box.MaxEdge.X
&& nodebox.MaxEdge.Z-d > box.MinEdge.Z
&& nodebox.MinEdge.Z+d < box.MaxEdge.Z
cbox.MaxEdge.X-d > box.MinEdge.X &&
cbox.MinEdge.X+d < box.MaxEdge.X &&
cbox.MaxEdge.Z-d > box.MinEdge.Z &&
cbox.MinEdge.Z+d < box.MaxEdge.Z
){
if(is_step_up[boxindex])
{
pos_f.Y += (cbox.MaxEdge.Y - box.MinEdge.Y);
box = box_0;
box.MinEdge += pos_f;
box.MaxEdge += pos_f;
}
if(fabs(cbox.MaxEdge.Y-box.MinEdge.Y) < 0.15*BS)
{
result.touching_ground = true;
}
// If object doesn't intersect with node, ignore node.
if(box.intersectsWithBox(nodebox) == false)
continue;
/*
Go through every axis
*/
v3f dirs[3] = {
v3f(0,0,1), // back-front
v3f(0,1,0), // top-bottom
v3f(1,0,0), // right-left
};
for(u16 i=0; i<3; i++)
{
/*
Calculate values along the axis
*/
f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
f32 objectmax = box.MaxEdge.dotProduct(dirs[i]);
f32 objectmin = box.MinEdge.dotProduct(dirs[i]);
f32 objectmax_old = oldbox.MaxEdge.dotProduct(dirs[i]);
f32 objectmin_old = oldbox.MinEdge.dotProduct(dirs[i]);
/*
Check collision for the axis.
Collision happens when object is going through a surface.
*/
bool negative_axis_collides =
(nodemax > objectmin && nodemax <= objectmin_old + d
&& speed_f.dotProduct(dirs[i]) < 0);
bool positive_axis_collides =
(nodemin < objectmax && nodemin >= objectmax_old - d
&& speed_f.dotProduct(dirs[i]) > 0);
bool main_axis_collides =
negative_axis_collides || positive_axis_collides;
/*
Check overlap of object and node in other axes
*/
bool other_axes_overlap = true;
for(u16 j=0; j<3; j++)
{
if(j == i)
continue;
f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
f32 objectmax = box.MaxEdge.dotProduct(dirs[j]);
f32 objectmin = box.MinEdge.dotProduct(dirs[j]);
if(!(nodemax - d > objectmin && nodemin + d < objectmax))
{
other_axes_overlap = false;
break;
if(is_unloaded[boxindex])
result.standing_on_unloaded = true;
}
}
/*
If this is a collision, revert the pos_f in the main
direction.
*/
if(other_axes_overlap && main_axis_collides)
{
speed_f -= speed_f.dotProduct(dirs[i]) * dirs[i];
pos_f -= pos_f.dotProduct(dirs[i]) * dirs[i];
pos_f += oldpos_f.dotProduct(dirs[i]) * dirs[i];
}
}
} // xyz
return result;
}
collisionMoveResult collisionMovePrecise(Map *map, f32 pos_max_d,
const core::aabbox3d<f32> &box_0,
f32 dtime, v3f &pos_f, v3f &speed_f)
{
collisionMoveResult final_result;
// Maximum time increment (for collision detection etc)
// time = distance / speed
f32 dtime_max_increment = pos_max_d / speed_f.getLength();
// Maximum time increment is 10ms or lower
if(dtime_max_increment > 0.01)
dtime_max_increment = 0.01;
// Don't allow overly huge dtime
if(dtime > 2.0)
dtime = 2.0;
f32 dtime_downcount = dtime;
u32 loopcount = 0;
do
{
loopcount++;
f32 dtime_part;
if(dtime_downcount > dtime_max_increment)
{
dtime_part = dtime_max_increment;
dtime_downcount -= dtime_part;
}
else
{
dtime_part = dtime_downcount;
/*
Setting this to 0 (no -=dtime_part) disables an infinite loop
when dtime_part is so small that dtime_downcount -= dtime_part
does nothing
*/
dtime_downcount = 0;
}
collisionMoveResult result = collisionMoveSimple(map, pos_max_d,
box_0, dtime_part, pos_f, speed_f);
if(result.touching_ground)
final_result.touching_ground = true;
}
while(dtime_downcount > 0.001);
return final_result;
}

View File

@ -21,42 +21,57 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define COLLISION_HEADER
#include "common_irrlicht.h"
#include <vector>
class Map;
struct collisionMoveResult
{
bool touching_ground;
bool in_liquid;
bool touching_lethal;
collisionMoveResult():
touching_ground(false),
in_liquid(false),
touching_lethal(false)
{}
};
// Moves using a single iteration; speed should not exceed pos_max_d/dtime
collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
const core::aabbox3d<f32> &box_0,
f32 dtime, v3f &pos_f, v3f &speed_f);
// Moves using as many iterations as needed
collisionMoveResult collisionMovePrecise(Map *map, f32 pos_max_d,
const core::aabbox3d<f32> &box_0,
f32 dtime, v3f &pos_f, v3f &speed_f);
enum CollisionType
{
COLLISION_FALL
COLLISION_FALL,
COLLISION_NODE
};
struct CollisionInfo
{
CollisionType t;
f32 speed;
v3s16 node_p; // COLLISION_NODE
v3f old_speed;
v3f new_speed;
CollisionInfo():
t(COLLISION_NODE),
node_p(-32768,-32768,-32768),
old_speed(0,0,0),
new_speed(0,0,0)
{}
};
struct collisionMoveResult
{
bool touching_ground;
bool in_liquid;
bool touching_lethal;
bool collides;
bool collides_xz;
bool standing_on_unloaded;
std::vector<CollisionInfo> collisions;
collisionMoveResult():
touching_ground(false),
in_liquid(false),
touching_lethal(false),
collides(false),
collides_xz(false),
standing_on_unloaded(false)
{}
};
// Moves using a single iteration; speed should not exceed pos_max_d/dtime
collisionMoveResult collisionMoveSimple(Map *map,
f32 pos_max_d, const aabb3f &box_0,
f32 stepheight, f32 dtime,
v3f &pos_f, v3f &speed_f, v3f &accel_f);
#endif

View File

@ -61,6 +61,8 @@ typedef core::vector2d<s32> v2s32;
typedef core::vector2d<u32> v2u32;
typedef core::vector2d<f32> v2f32;
typedef core::aabbox3d<f32> aabb3f;
#ifdef _MSC_VER
// Windows
typedef unsigned long long u64;

View File

@ -107,7 +107,7 @@ struct CraftDef {
*/
InventoryItem *craft_get_result(InventoryItem **items)
{
static CraftDef defs[33];
static CraftDef defs[35];
static int defs_init = 0;
// only initialise (and hence allocate) these once
@ -474,6 +474,27 @@ InventoryItem *craft_get_result(InventoryItem **items)
defs[defs_init].item = new CraftItem("apple_iron", 1);
defs_init++;
}
// cobble slabs
{
defs[defs_init].specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
defs[defs_init].specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
defs[defs_init].specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
defs[defs_init].item = new MaterialItem(CONTENT_COBBLE_SLAB, 3);
defs_init++;
}
// cobble stairs
{
defs[defs_init].specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
defs[defs_init].specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
defs[defs_init].specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
defs[defs_init].specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
defs[defs_init].specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
defs[defs_init].specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
defs[defs_init].item = new MaterialItem(CONTENT_COBBLE_STAIR, 4);
defs_init++;
}
}
for (int i=0; i<defs_init; i++) {

View File

@ -40,82 +40,65 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// If you specified 0,0,1,1 for each face, that would be the
// same as passing NULL.
void makeCuboid(video::SMaterial &material, MeshCollector *collector,
AtlasPointer* pa, video::SColor &c,
v3f &pos, f32 rx, f32 ry, f32 rz, f32* txc)
video::SColor &c, const aabb3f &box, const f32* txc)
{
f32 tu0=pa->x0();
f32 tu1=pa->x1();
f32 tv0=pa->y0();
f32 tv1=pa->y1();
f32 txus=tu1-tu0;
f32 txvs=tv1-tv0;
v3f min = box.MinEdge;
v3f max = box.MaxEdge;
video::S3DVertex v[4] =
if(txc == NULL)
{
video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv1),
video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv1),
video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv0),
video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv0)
static const f32 txc_default[24] = {
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1
};
txc = txc_default;
}
video::S3DVertex vertices[24] =
{
// up
video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c, txc[0],txc[1]),
video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c, txc[2],txc[1]),
video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c, txc[2],txc[3]),
video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c, txc[0],txc[3]),
// down
video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c, txc[4],txc[5]),
video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c, txc[6],txc[5]),
video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c, txc[6],txc[7]),
video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c, txc[4],txc[7]),
// right
video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c, txc[ 8],txc[9]),
video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c, txc[10],txc[9]),
video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c, txc[10],txc[11]),
video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c, txc[ 8],txc[11]),
// left
video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c, txc[12],txc[13]),
video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c, txc[14],txc[13]),
video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]),
video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]),
// back
video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]),
video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]),
video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]),
video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]),
// front
video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]),
video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]),
video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]),
video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
};
for(int i=0;i<6;i++)
{
switch(i)
{
case 0: // top
v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
v[2].Pos.X= rx; v[2].Pos.Y= ry; v[2].Pos.Z= rz;
v[3].Pos.X= rx; v[3].Pos.Y= ry, v[3].Pos.Z=-rz;
break;
case 1: // back
v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
break;
case 2: //right
v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
break;
case 3: // front
v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
break;
case 4: // left
v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
break;
case 5: // bottom
v[0].Pos.X= rx; v[0].Pos.Y=-ry; v[0].Pos.Z= rz;
v[1].Pos.X=-rx; v[1].Pos.Y=-ry; v[1].Pos.Z= rz;
v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
break;
}
if(txc!=NULL)
{
v[0].TCoords.X=tu0+txus*txc[0]; v[0].TCoords.Y=tv0+txvs*txc[3];
v[1].TCoords.X=tu0+txus*txc[2]; v[1].TCoords.Y=tv0+txvs*txc[3];
v[2].TCoords.X=tu0+txus*txc[2]; v[2].TCoords.Y=tv0+txvs*txc[1];
v[3].TCoords.X=tu0+txus*txc[0]; v[3].TCoords.Y=tv0+txvs*txc[1];
txc+=4;
}
for(u16 i=0; i<4; i++)
v[i].Pos += pos;
u16 indices[] = {0,1,2,2,3,0};
collector->append(material, v, 4, indices, 6);
// Add to mesh collector
for(s32 j=0; j<24; j+=4)
{
collector->append(material, vertices+j, 4, indices, 6);
}
}
#endif
@ -127,7 +110,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
Some settings
*/
bool new_style_water = g_settings->getBool("new_style_water");
bool invisible_stone = g_settings->getBool("invisible_stone");
float node_liquid_level = 1.0;
if(new_style_water)
@ -135,7 +117,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
// New-style leaves material
// leaves material
video::SMaterial material_leaves1;
material_leaves1.setFlag(video::EMF_LIGHTING, false);
material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
@ -165,6 +147,16 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
g_texturesource->getTextureId("wood.png"));
material_wood.setTexture(0, pa_wood.atlas);
// Cobble material
video::SMaterial material_cobble;
material_cobble.setFlag(video::EMF_LIGHTING, false);
material_cobble.setFlag(video::EMF_BILINEAR_FILTER, false);
material_cobble.setFlag(video::EMF_FOG_ENABLE, true);
material_cobble.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
AtlasPointer pa_cobble = g_texturesource->getTexture(
g_texturesource->getTextureId("cobble.png"));
material_cobble.setTexture(0, pa_cobble.atlas);
// General ground material for special output
// Texture is modified just before usage
video::SMaterial material_general;
@ -216,6 +208,11 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
g_texturesource->getTextureId("junglegrass.png"));
material_junglegrass.setTexture(0, pa_junglegrass.atlas);
// sign material
AtlasPointer ap_sign_wall = g_texturesource->getTexture("sign_wall.png");
// ladder material
AtlasPointer ap_ladder = g_texturesource->getTexture("ladder.png");
// generic material pointer
video::SMaterial *material_current;
AtlasPointer *pa_current;
@ -231,8 +228,11 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
/*
Add torches to mesh
*/
switch (content_features(n).liquid_type) {
case LIQUID_FLOWING:
switch (content_features(n).draw_type) {
case CDT_CUBELIKE:
case CDT_AIRLIKE:
break;
case CDT_LIQUID:
{
assert(content_features(n).special_material);
video::SMaterial &liquid_material =
@ -518,7 +518,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
Add water sources to mesh if using new style
*/
break;
case LIQUID_SOURCE:
case CDT_LIQUID_SOURCE:
if (new_style_water)
{
assert(content_features(n).special_material);
@ -559,9 +559,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
collector.append(liquid_material, vertices, 4, indices, 6);
}
break;
case LIQUID_NONE:
switch (n.getContent()) {
case CONTENT_TORCH:
case CDT_TORCHLIKE:
{
v3s16 dir = unpackDir(n.param2);
@ -631,9 +629,19 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
Signs on walls
*/
break;
case CONTENT_SIGN_WALL:
case CDT_SIGNLIKE:
{
AtlasPointer ap = g_texturesource->getTexture("sign_wall.png");
switch (n.getContent()) {
case CONTENT_SIGN_WALL:
pa_current = &ap_sign_wall;
break;
case CONTENT_LADDER:
pa_current = &ap_ladder;
break;
default:
pa_current = &ap_sign_wall;
break;
}
// Set material
video::SMaterial material;
@ -643,7 +651,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
material.setFlag(video::EMF_FOG_ENABLE, true);
material.MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material.setTexture(0, ap.atlas);
material.setTexture(0, pa_current->atlas);
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
video::SColor c = MapBlock_LightColor(255, l);
@ -653,13 +661,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
video::S3DVertex vertices[4] =
{
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
ap.x0(), ap.y1()),
pa_current->x0(), pa_current->y1()),
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y1()),
pa_current->x1(), pa_current->y1()),
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y0()),
pa_current->x1(), pa_current->y0()),
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
ap.x0(), ap.y0()),
pa_current->x0(), pa_current->y0()),
};
v3s16 dir = unpackDir(n.param2);
@ -686,103 +694,50 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Add to mesh collector
collector.append(material, vertices, 4, indices, 6);
}
/*
Add flowing liquid to mesh
*/
break;
/*
Add leaves if using new style
*/
break;
case CONTENT_LEAVES:
{
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
video::SColor c = MapBlock_LightColor(255, l);
for(u32 j=0; j<6; j++)
{
video::S3DVertex vertices[4] =
{
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)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(0);
}
else if(j == 1)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(180);
}
else if(j == 2)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(-90);
}
else if(j == 3)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(90);
}
else if(j == 4)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateYZBy(-90);
}
else if(j == 5)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateYZBy(90);
}
for(u16 i=0; i<4; i++)
{
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
}
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(material_leaves1, vertices, 4, indices, 6);
}
}
/*
Add glass
*/
break;
case CONTENT_GLASS:
case CDT_GLASSLIKE:
{
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
video::SColor c = MapBlock_LightColor(255, l);
switch (n.getContent()) {
case CONTENT_GLASS:
pa_current = &pa_glass;
material_current = &material_glass;
break;
case CONTENT_LEAVES:
pa_current = &pa_leaves1;
material_current = &material_leaves1;
break;
default:
pa_current = &pa_glass;
material_current = &material_glass;
break;
}
for(u32 j=0; j<6; j++)
{
// Check this neighbor
v3s16 n2p = blockpos_nodes + p + g_6dirs[j];
MapNode n2 = data->m_vmanip.getNodeNoEx(n2p);
// Don't make face if neighbor is of same type
// if(n2.getContent() == n.getContent())
// continue;
// The face at Z+
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
pa_glass.x0(), pa_glass.y1()),
pa_current->x0(), pa_current->y1()),
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
pa_glass.x1(), pa_glass.y1()),
pa_current->x1(), pa_current->y1()),
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
pa_glass.x1(), pa_glass.y0()),
pa_current->x1(), pa_current->y0()),
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
pa_glass.x0(), pa_glass.y0()),
pa_current->x0(), pa_current->y0()),
};
// Rotations in the g_6dirs format
@ -826,14 +781,14 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(material_glass, vertices, 4, indices, 6);
collector.append(*material_current, vertices, 4, indices, 6);
}
}
/*
Add fence
*/
break;
case CONTENT_FENCE:
case CDT_FENCELIKE:
{
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
video::SColor c = MapBlock_LightColor(255, l);
@ -844,26 +799,32 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// The post - always present
v3f pos = intToFloat(p+blockpos_nodes, BS);
// The post - always present
aabb3f post(-post_rad,-BS/2,-post_rad,post_rad,BS/2,post_rad);
post.MinEdge += pos;
post.MaxEdge += pos;
f32 postuv[24]={
0.4,0.4,0.6,0.6,
0.35,0,0.65,1,
0.35,0,0.65,1,
0.35,0,0.65,1,
0.35,0,0.65,1,
0.4,0.4,0.6,0.6};
makeCuboid(material_wood, &collector,
&pa_wood, c, pos,
post_rad,BS/2,post_rad, postuv);
makeCuboid(material_wood, &collector, c, post, postuv);
// Now a section of fence, +X, if there's a post there
v3s16 p2 = p;
p2.X++;
MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
if(n2.getContent() == CONTENT_FENCE)
const ContentFeatures *f2 = &content_features(n2);
if(f2->draw_type == CDT_FENCELIKE)
{
pos = intToFloat(p+blockpos_nodes, BS);
pos.X += BS/2;
pos.Y += BS/4;
aabb3f bar(-bar_len+BS/2,-bar_rad+BS/4,-bar_rad,
bar_len+BS/2,bar_rad+BS/4,bar_rad);
bar.MinEdge += pos;
bar.MaxEdge += pos;
f32 xrailuv[24]={
0,0.4,1,0.6,
0,0.4,1,0.6,
@ -871,25 +832,23 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
0,0.4,1,0.6,
0,0.4,1,0.6,
0,0.4,1,0.6};
makeCuboid(material_wood, &collector,
&pa_wood, c, pos,
bar_len,bar_rad,bar_rad, xrailuv);
pos.Y -= BS/2;
makeCuboid(material_wood, &collector,
&pa_wood, c, pos,
bar_len,bar_rad,bar_rad, xrailuv);
makeCuboid(material_wood, &collector, c, bar, xrailuv);
bar.MinEdge.Y -= BS/2;
bar.MaxEdge.Y -= BS/2;
makeCuboid(material_wood, &collector, c, bar, xrailuv);
}
// Now a section of fence, +Z, if there's a post there
p2 = p;
p2.Z++;
n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
if(n2.getContent() == CONTENT_FENCE)
f2 = &content_features(n2);
if(f2->draw_type == CDT_FENCELIKE)
{
pos = intToFloat(p+blockpos_nodes, BS);
pos.Z += BS/2;
pos.Y += BS/4;
aabb3f bar(-bar_rad,-bar_rad+BS/4,-bar_len+BS/2,
bar_rad,bar_rad+BS/4,bar_len+BS/2);
bar.MinEdge += pos;
bar.MaxEdge += pos;
f32 zrailuv[24]={
0,0.4,1,0.6,
0,0.4,1,0.6,
@ -897,100 +856,32 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
0,0.4,1,0.6,
0,0.4,1,0.6,
0,0.4,1,0.6};
makeCuboid(material_wood, &collector,
&pa_wood, c, pos,
bar_rad,bar_rad,bar_len, zrailuv);
pos.Y -= BS/2;
makeCuboid(material_wood, &collector,
&pa_wood, c, pos,
bar_rad,bar_rad,bar_len, zrailuv);
makeCuboid(material_wood, &collector, c, bar, zrailuv);
bar.MinEdge.Y -= BS/2;
bar.MaxEdge.Y -= BS/2;
makeCuboid(material_wood, &collector, c, bar, zrailuv);
}
}
#if 1
/*
Add stones with minerals if stone is invisible
*/
break;
case CONTENT_STONE:
if (invisible_stone && n.getMineral() != MINERAL_NONE)
{
for(u32 j=0; j<6; j++)
{
// NOTE: Hopefully g_6dirs[j] is the right direction...
v3s16 dir = g_6dirs[j];
u8 l = 255;
video::SColor c = MapBlock_LightColor(255, l);
// Get the right texture
TileSpec ts = n.getTile(dir);
AtlasPointer ap = ts.texture;
material_general.setTexture(0, ap.atlas);
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
ap.x0(), ap.y1()),
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y1()),
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y0()),
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
ap.x0(), ap.y0()),
};
if(j == 0)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(0);
}
else if(j == 1)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(180);
}
else if(j == 2)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(-90);
}
else if(j == 3)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(90);
}
else if(j == 4)
for(u16 i=0; i<4; i++)
{
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
}
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(material_general, vertices, 4, indices, 6);
}
}
#endif
break;
case CONTENT_RAIL:
case CDT_RAILLIKE:
{
bool is_rail_x [] = { false, false }; /* x-1, x+1 */
bool is_rail_z [] = { false, false }; /* z-1, z+1 */
content_t type = n.getContent();
MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z));
MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z));
MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1));
MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1));
if(n_minus_x.getContent() == CONTENT_RAIL)
if(n_minus_x.getContent() == type)
is_rail_x[0] = true;
if(n_plus_x.getContent() == CONTENT_RAIL)
if(n_plus_x.getContent() == type)
is_rail_x[1] = true;
if(n_minus_z.getContent() == CONTENT_RAIL)
if(n_minus_z.getContent() == type)
is_rail_z[0] = true;
if(n_plus_z.getContent() == CONTENT_RAIL)
if(n_plus_z.getContent() == type)
is_rail_z[1] = true;
int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1];
@ -1083,63 +974,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
collector.append(material_rail, vertices, 4, indices, 6);
}
break;
case CONTENT_LADDER:
{
AtlasPointer ap = g_texturesource->getTexture("ladder.png");
// Set material
video::SMaterial material_ladder;
material_ladder.setFlag(video::EMF_LIGHTING, false);
material_ladder.setFlag(video::EMF_BACK_FACE_CULLING, false);
material_ladder.setFlag(video::EMF_BILINEAR_FILTER, false);
material_ladder.setFlag(video::EMF_FOG_ENABLE, true);
material_ladder.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material_ladder.setTexture(0, ap.atlas);
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
video::SColor c(255,l,l,l);
float d = (float)BS/16;
// Assume wall is at X+
video::S3DVertex vertices[4] =
{
video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
ap.x0(), ap.y1()),
video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y1()),
video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
ap.x1(), ap.y0()),
video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
ap.x0(), ap.y0()),
};
v3s16 dir = unpackDir(n.param2);
for(s32 i=0; i<4; i++)
{
if(dir == v3s16(1,0,0))
vertices[i].Pos.rotateXZBy(0);
if(dir == v3s16(-1,0,0))
vertices[i].Pos.rotateXZBy(180);
if(dir == v3s16(0,0,1))
vertices[i].Pos.rotateXZBy(90);
if(dir == v3s16(0,0,-1))
vertices[i].Pos.rotateXZBy(-90);
if(dir == v3s16(0,-1,0))
vertices[i].Pos.rotateXYBy(-90);
if(dir == v3s16(0,1,0))
vertices[i].Pos.rotateXYBy(90);
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
}
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(material_ladder, vertices, 4, indices, 6);
}
break;
case CONTENT_JUNGLEGRASS:
case CDT_PLANTLIKE_LGE:
{
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
video::SColor c = MapBlock_LightColor(255, l);
@ -1191,9 +1026,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
}
}
break;
case CONTENT_PAPYRUS:
case CONTENT_SAPLING:
case CONTENT_APPLE:
case CDT_PLANTLIKE:
{
switch (n.getContent()) {
case CONTENT_PAPYRUS:
@ -1201,14 +1034,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
pa_current = &pa_papyrus;
break;
case CONTENT_SAPLING:
default:
material_current = &material_sapling;
pa_current = &pa_sapling;
break;
case CONTENT_APPLE:
default:
material_current = &material_apple;
pa_current = &pa_apple;
break;
}
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
video::SColor c = MapBlock_LightColor(255, l);
@ -1259,7 +1088,123 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
}
}
break;
case CDT_PLANTLIKE_SML:
{
switch (n.getContent()) {
case CONTENT_APPLE:
default:
material_current = &material_apple;
pa_current = &pa_apple;
break;
}
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
video::SColor c = MapBlock_LightColor(255, l);
for(u32 j=0; j<4; j++)
{
video::S3DVertex vertices[4] =
{
video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
pa_current->x0(), pa_current->y1()),
video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
pa_current->x1(), pa_current->y1()),
video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
pa_current->x1(), pa_current->y0()),
video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
pa_current->x0(), pa_current->y0()),
};
if(j == 0)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(45);
}
else if(j == 1)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(-45);
}
else if(j == 2)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(135);
}
else if(j == 3)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateXZBy(-135);
}
for(u16 i=0; i<4; i++)
{
vertices[i].Pos *= 0.8;
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
}
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
collector.append(*material_current, vertices, 4, indices, 6);
}
}
break;
case CDT_NODEBOX:
{
material_current = &material_cobble;
u32 lt = 0;
u8 ld = 0;
for (s16 tx=-1; tx<2; tx++) {
for (s16 ty=-1; ty<2; ty++) {
for (s16 tz=-1; tz<2; tz++) {
if (!tx && !ty && !tz)
continue;
MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+tx,y+ty,z+tz));
if (ty<1 && n.getContent() != CONTENT_AIR)
continue;
lt += decode_light(n.getLightBlend(data->m_daynight_ratio));
ld++;
}
}
}
u8 l = lt/ld;
video::SColor c = MapBlock_LightColor(255, l);
v3f pos = intToFloat(p+blockpos_nodes, BS);
std::vector<aabb3f> boxes = content_features(n).getNodeBoxes();
for(std::vector<aabb3f>::iterator
i = boxes.begin();
i != boxes.end(); i++)
{
aabb3f box = *i;
box.MinEdge += pos;
box.MaxEdge += pos;
// Compute texture coords
f32 tx1 = (i->MinEdge.X/BS)+0.5;
f32 ty1 = (i->MinEdge.Y/BS)+0.5;
f32 tz1 = (i->MinEdge.Z/BS)+0.5;
f32 tx2 = (i->MaxEdge.X/BS)+0.5;
f32 ty2 = (i->MaxEdge.Y/BS)+0.5;
f32 tz2 = (i->MaxEdge.Z/BS)+0.5;
f32 txc[24] = {
// up
tx1, 1-tz2, tx2, 1-tz1,
// down
tx1, tz1, tx2, tz2,
// right
tz1, 1-ty2, tz2, 1-ty1,
// left
1-tz2, 1-ty2, 1-tz1, 1-ty1,
// back
1-tx2, 1-ty2, 1-tx1, 1-ty1,
// front
tx1, 1-ty2, tx2, 1-ty1,
};
makeCuboid(*material_current, &collector, c, box, txc);
}
}
break;
}
}
}

View File

@ -119,6 +119,7 @@ void content_mapnode_init()
f->setAllTextures("stone.png");
f->setInventoryTextureCube("stone.png", "stone.png", "stone.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->often_contains_mineral = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 1";
@ -132,6 +133,7 @@ void content_mapnode_init()
f->setTexture(0, "grass.png");
f->setTexture(1, "mud.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_MUD)+" 1";
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
@ -140,6 +142,7 @@ void content_mapnode_init()
f = &content_features(i);
f->setAllTextures("dirt.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_MUD)+" 1";
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
@ -149,6 +152,7 @@ void content_mapnode_init()
f->setAllTextures("mud.png");
f->setInventoryTextureCube("mud.png", "mud.png", "mud.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
@ -158,6 +162,7 @@ void content_mapnode_init()
f->setAllTextures("sand.png");
f->setInventoryTextureCube("sand.png", "sand.png", "sand.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
@ -167,6 +172,7 @@ void content_mapnode_init()
f->setAllTextures("gravel.png");
f->setInventoryTextureCube("gravel.png", "gravel.png", "gravel.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setDirtLikeDiggingProperties(f->digging_properties, 1.75);
@ -176,6 +182,7 @@ void content_mapnode_init()
f->setAllTextures("sandstone.png");
f->setInventoryTextureCube("sandstone.png", "sandstone.png", "sandstone.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAND)+" 4";
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
@ -185,6 +192,7 @@ void content_mapnode_init()
f->setAllTextures("clay.png");
f->setInventoryTextureCube("clay.png", "clay.png", "clay.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("CraftItem lump_of_clay 4");
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
@ -194,6 +202,7 @@ void content_mapnode_init()
f->setAllTextures("brick.png");
f->setInventoryTextureCube("brick.png", "brick.png", "brick.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("CraftItem clay_brick 4");
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
@ -205,6 +214,7 @@ void content_mapnode_init()
f->setTexture(1, "tree_top.png");
f->setInventoryTextureCube("tree_top.png", "tree.png", "tree.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
@ -216,6 +226,7 @@ void content_mapnode_init()
f->setTexture(1, "jungletree_top.png");
f->setInventoryTextureCube("jungletree_top.png", "jungletree.png", "jungletree.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
//f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
@ -226,6 +237,7 @@ void content_mapnode_init()
f->used_texturenames["junglegrass.png"] = true;
f->light_propagates = true;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_PLANTLIKE_LGE;
//f->is_ground_content = true;
f->air_equivalent = false; // grass grows underneath
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
@ -238,6 +250,7 @@ void content_mapnode_init()
f->light_propagates = true;
//f->param_type = CPT_MINERAL;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_GLASSLIKE;
//f->is_ground_content = true;
if(new_style_leaves)
{
@ -262,6 +275,7 @@ void content_mapnode_init()
f->setTexture(1, "cactus_top.png");
f->setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
@ -272,6 +286,7 @@ void content_mapnode_init()
f->used_texturenames["papyrus.png"] = true;
f->light_propagates = true;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_PLANTLIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->solidness = 0; // drawn separately, makes no faces
@ -285,6 +300,7 @@ void content_mapnode_init()
f->setTexture(1, "wood.png");
f->setInventoryTextureCube("wood.png", "bookshelf.png", "bookshelf.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
@ -293,6 +309,7 @@ void content_mapnode_init()
f->light_propagates = true;
f->sunlight_propagates = true;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_GLASSLIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->solidness = 0; // drawn separately, makes no faces
@ -305,6 +322,7 @@ void content_mapnode_init()
f = &content_features(i);
f->light_propagates = true;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_FENCELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->solidness = 0; // drawn separately, makes no faces
@ -319,6 +337,7 @@ void content_mapnode_init()
f->used_texturenames["rail.png"] = true;
f->light_propagates = true;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_RAILLIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->solidness = 0; // drawn separately, makes no faces
@ -332,6 +351,7 @@ void content_mapnode_init()
f->used_texturenames["ladder.png"] = true;
f->light_propagates = true;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_SIGNLIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
f->wall_mounted = true;
@ -346,6 +366,7 @@ void content_mapnode_init()
f = &content_features(i);
f->setAllTextures("borderstone.png");
f->setInventoryTextureCube("borderstone.png", "borderstone.png", "borderstone.png");
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
if(f->initial_metadata == NULL)
@ -356,6 +377,7 @@ void content_mapnode_init()
f = &content_features(i);
f->setAllTextures("wood.png");
f->setInventoryTextureCube("wood.png", "wood.png", "wood.png");
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
@ -364,6 +386,7 @@ void content_mapnode_init()
f = &content_features(i);
f->setAllTextures("mese.png");
f->setInventoryTextureCube("mese.png", "mese.png", "mese.png");
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 0.5);
@ -373,6 +396,7 @@ void content_mapnode_init()
f->setAllTextures("cotton.png");
f->setInventoryTextureCube("cotton.png", "cotton.png", "cotton.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
@ -380,6 +404,7 @@ void content_mapnode_init()
i = CONTENT_AIR;
f = &content_features(i);
f->param_type = CPT_LIGHT;
f->draw_type = CDT_AIRLIKE;
f->light_propagates = true;
f->sunlight_propagates = true;
f->solidness = 0;
@ -393,6 +418,7 @@ void content_mapnode_init()
f = &content_features(i);
f->setInventoryTextureCube("water.png", "water.png", "water.png");
f->param_type = CPT_LIGHT;
f->draw_type = CDT_LIQUID;
f->light_propagates = true;
f->solidness = 0; // Drawn separately, makes no faces
f->visual_solidness = 1;
@ -456,6 +482,7 @@ void content_mapnode_init()
#endif
}
f->param_type = CPT_LIGHT;
f->draw_type = CDT_LIQUID_SOURCE;
f->light_propagates = true;
f->walkable = false;
f->pointable = false;
@ -491,6 +518,7 @@ void content_mapnode_init()
f->setInventoryTextureCube("lava.png", "lava.png", "lava.png");
f->used_texturenames["lava.png"] = true;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_LIQUID;
f->light_propagates = false;
f->light_source = LIGHT_MAX-1;
f->solidness = 0; // Drawn separately, makes no faces
@ -553,6 +581,7 @@ void content_mapnode_init()
#endif
}
f->param_type = CPT_LIGHT;
f->draw_type = CDT_LIQUID_SOURCE;
f->light_propagates = false;
f->light_source = LIGHT_MAX-1;
f->walkable = false;
@ -593,6 +622,7 @@ void content_mapnode_init()
f->used_texturenames["torch_on_floor.png"] = true;
f->used_texturenames["torch.png"] = true;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_TORCHLIKE;
f->light_propagates = true;
f->sunlight_propagates = true;
f->solidness = 0; // drawn separately, makes no faces
@ -608,6 +638,7 @@ void content_mapnode_init()
f->setInventoryTexture("sign_wall.png");
f->used_texturenames["sign_wall.png"] = true;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_SIGNLIKE;
f->light_propagates = true;
f->sunlight_propagates = true;
f->solidness = 0; // drawn separately, makes no faces
@ -622,6 +653,7 @@ void content_mapnode_init()
i = CONTENT_CHEST;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->draw_type = CDT_CUBELIKE;
f->setAllTextures("chest_side.png");
f->setTexture(0, "chest_top.png");
f->setTexture(1, "chest_top.png");
@ -636,6 +668,7 @@ void content_mapnode_init()
i = CONTENT_LOCKABLE_CHEST;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->draw_type = CDT_CUBELIKE;
f->setAllTextures("chest_side.png");
f->setTexture(0, "chest_top.png");
f->setTexture(1, "chest_top.png");
@ -650,6 +683,7 @@ void content_mapnode_init()
i = CONTENT_FURNACE;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->draw_type = CDT_CUBELIKE;
f->setAllTextures("furnace_side.png");
f->setTexture(5, "furnace_front.png"); // Z-
f->setInventoryTextureCube("furnace_side.png", "furnace_front.png", "furnace_side.png");
@ -663,6 +697,7 @@ void content_mapnode_init()
f->setAllTextures("cobble.png");
f->setInventoryTextureCube("cobble.png", "cobble.png", "cobble.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 0.9);
@ -672,6 +707,7 @@ void content_mapnode_init()
f->setAllTextures("mossycobble.png");
f->setInventoryTextureCube("mossycobble.png", "mossycobble.png", "mossycobble.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 0.8);
@ -681,6 +717,7 @@ void content_mapnode_init()
f->setAllTextures("steel_block.png");
f->setInventoryTextureCube("steel_block.png", "steel_block.png", "steel_block.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_CUBELIKE;
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 5.0);
@ -688,6 +725,7 @@ void content_mapnode_init()
i = CONTENT_NC;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->draw_type = CDT_CUBELIKE;
f->setAllTextures("nc_side.png");
f->setTexture(5, "nc_front.png"); // Z-
f->setTexture(4, "nc_back.png"); // Z+
@ -697,6 +735,7 @@ void content_mapnode_init()
i = CONTENT_NC_RB;
f = &content_features(i);
f->draw_type = CDT_CUBELIKE;
f->setAllTextures("nc_rb.png");
f->setInventoryTextureCube("nc_rb.png", "nc_rb.png", "nc_rb.png");
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
@ -705,6 +744,7 @@ void content_mapnode_init()
i = CONTENT_SAPLING;
f = &content_features(i);
f->param_type = CPT_LIGHT;
f->draw_type = CDT_PLANTLIKE;
f->setAllTextures("sapling.png");
f->setInventoryTexture("sapling.png");
f->used_texturenames["sapling.png"] = true;
@ -720,6 +760,7 @@ void content_mapnode_init()
f->setInventoryTexture("apple.png");
f->used_texturenames["apple.png"] = true;
f->param_type = CPT_LIGHT;
f->draw_type = CDT_PLANTLIKE_SML;
f->light_propagates = true;
f->sunlight_propagates = true;
f->solidness = 0; // drawn separately, makes no faces
@ -728,6 +769,495 @@ void content_mapnode_init()
f->dug_item = std::string("CraftItem apple 1");
f->digging_properties.set("", DiggingProperties(true, 0.0, 0));
// slabs
i = CONTENT_COBBLE_SLAB;
f = &content_features(i);
f->setAllTextures("cobble.png");
f->setInventoryTextureSlab("cobble.png", "cobble.png", "cobble.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
setStoneLikeDiggingProperties(f->digging_properties, 0.9);
i = CONTENT_MOSSYCOBBLE_SLAB;
f = &content_features(i);
f->setAllTextures("mossycobble.png");
f->setInventoryTextureSlab("mossycobble.png", "mossycobble.png", "mossycobble.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
setStoneLikeDiggingProperties(f->digging_properties, 0.8);
i = CONTENT_STONE_SLAB;
f = &content_features(i);
f->setAllTextures("stone.png");
f->setInventoryTextureSlab("stone.png", "stone.png", "stone.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_WOOD_SLAB;
f = &content_features(i);
f->setAllTextures("wood.png");
f->setInventoryTextureSlab("wood.png", "wood.png", "wood.png");
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
i = CONTENT_JUNGLE_SLAB;
f = &content_features(i);
f->setAllTextures("junglewood.png");
f->setInventoryTextureSlab("junglewood.png", "junglewood.png", "junglewood.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
//f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_BRICK_SLAB;
f = &content_features(i);
f->setAllTextures("brick.png");
f->setInventoryTextureSlab("brick.png", "brick.png", "brick.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("CraftItem clay_brick 4");
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_SANDSTONE_SLAB;
f = &content_features(i);
f->setAllTextures("sandstone.png");
f->setInventoryTextureSlab("sandstone.png", "sandstone.png", "sandstone.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAND)+" 4";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
// upside down slabs
i = CONTENT_COBBLE_SLAB_UD;
f = &content_features(i);
f->setAllTextures("cobble.png");
f->setInventoryTextureSlab("cobble.png", "cobble.png", "cobble.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 0.9);
i = CONTENT_MOSSYCOBBLE_SLAB_UD;
f = &content_features(i);
f->setAllTextures("mossycobble.png");
f->setInventoryTextureSlab("mossycobble.png", "mossycobble.png", "mossycobble.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 0.8);
i = CONTENT_STONE_SLAB_UD;
f = &content_features(i);
f->setAllTextures("stone.png");
f->setInventoryTextureSlab("stone.png", "stone.png", "stone.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_WOOD_SLAB_UD;
f = &content_features(i);
f->setAllTextures("wood.png");
f->setInventoryTextureSlab("wood.png", "wood.png", "wood.png");
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
i = CONTENT_JUNGLE_SLAB_UD;
f = &content_features(i);
f->setAllTextures("junglewood.png");
f->setInventoryTextureSlab("junglewood.png", "junglewood.png", "junglewood.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
//f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_JUNGLE_SLAB)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_BRICK_SLAB_UD;
f = &content_features(i);
f->setAllTextures("brick.png");
f->setInventoryTextureSlab("brick.png", "brick.png", "brick.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("CraftItem clay_brick 4");
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_SANDSTONE_SLAB_UD;
f = &content_features(i);
f->setAllTextures("sandstone.png");
f->setInventoryTextureSlab("sandstone.png", "sandstone.png", "sandstone.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAND)+" 4";
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
// stairs
i = CONTENT_COBBLE_STAIR;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("cobble.png");
f->setInventoryTextureStair("cobble.png", "cobble.png", "cobble.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
f->addNodeBox(core::aabbox3d<f32>(
-0.5*BS,
0.,
0.,
0.5*BS,
0.5*BS,
0.5*BS
));
setStoneLikeDiggingProperties(f->digging_properties, 0.9);
i = CONTENT_MOSSYCOBBLE_STAIR;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("mossycobble.png");
f->setInventoryTextureStair("mossycobble.png", "mossycobble.png", "mossycobble.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
f->addNodeBox(core::aabbox3d<f32>(
-0.5*BS,
0.,
0.,
0.5*BS,
0.5*BS,
0.5*BS
));
setStoneLikeDiggingProperties(f->digging_properties, 0.8);
i = CONTENT_STONE_STAIR;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("stone.png");
f->setInventoryTextureStair("stone.png", "stone.png", "stone.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->often_contains_mineral = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
f->addNodeBox(core::aabbox3d<f32>(
-0.5*BS,
0.,
0.,
0.5*BS,
0.5*BS,
0.5*BS
));
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_WOOD_STAIR;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->draw_type = CDT_NODEBOX;
f->setAllTextures("wood.png");
f->setInventoryTextureStair("wood.png", "wood.png", "wood.png");
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
f->addNodeBox(core::aabbox3d<f32>(
-0.5*BS,
0.,
0.,
0.5*BS,
0.5*BS,
0.5*BS
));
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
i = CONTENT_JUNGLE_STAIR;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("junglewood.png");
f->setInventoryTextureStair("junglewood.png", "junglewood.png", "junglewood.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
//f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
f->addNodeBox(core::aabbox3d<f32>(
-0.5*BS,
0.,
0.,
0.5*BS,
0.5*BS,
0.5*BS
));
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_BRICK_STAIR;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("brick.png");
f->setInventoryTextureStair("brick.png", "brick.png", "brick.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->is_ground_content = true;
f->dug_item = std::string("CraftItem clay_brick 4");
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
f->addNodeBox(core::aabbox3d<f32>(
-0.5*BS,
0.,
0.,
0.5*BS,
0.5*BS,
0.5*BS
));
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_SANDSTONE_STAIR;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("sandstone.png");
f->setInventoryTextureStair("sandstone.png", "sandstone.png", "sandstone.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAND)+" 4";
f->setNodeBox(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0,
0.5*BS
));
f->addNodeBox(core::aabbox3d<f32>(
-0.5*BS,
0.,
0.,
0.5*BS,
0.5*BS,
0.5*BS
));
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
// upside down stairs
i = CONTENT_COBBLE_STAIR_UD;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("cobble.png");
f->setInventoryTextureStair("cobble.png", "cobble.png", "cobble.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE_STAIR)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 0.9);
i = CONTENT_MOSSYCOBBLE_STAIR_UD;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("mossycobble.png");
f->setInventoryTextureStair("mossycobble.png", "mossycobble.png", "mossycobble.png");
f->param_type = CPT_NONE;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_MOSSYCOBBLE_STAIR)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 0.8);
i = CONTENT_STONE_STAIR_UD;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("stone.png");
f->setInventoryTextureStair("stone.png", "stone.png", "stone.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_STONE_STAIR)+" 1";
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_WOOD_STAIR_UD;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("wood.png");
f->setInventoryTextureStair("wood.png", "wood.png", "wood.png");
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_WOOD_STAIR)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 0.75);
i = CONTENT_JUNGLE_STAIR_UD;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("junglewood.png");
f->setInventoryTextureStair("junglewood.png", "junglewood.png", "junglewood.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
//f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_JUNGLE_STAIR)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_BRICK_STAIR_UD;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("brick.png");
f->setInventoryTextureStair("brick.png", "brick.png", "brick.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("CraftItem clay_brick 4");
setStoneLikeDiggingProperties(f->digging_properties, 1.0);
i = CONTENT_SANDSTONE_STAIR_UD;
f = &content_features(i);
f->param_type = CPT_FACEDIR_SIMPLE;
f->setAllTextures("sandstone.png");
f->setInventoryTextureStair("sandstone.png", "sandstone.png", "sandstone.png");
f->param_type = CPT_MINERAL;
f->draw_type = CDT_NODEBOX;
f->solidness = 0; // drawn separately, makes no faces
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_SAND)+" 4";
setDirtLikeDiggingProperties(f->digging_properties, 1.0);
// NOTE: Remember to add frequently used stuff to the texture atlas in tile.cpp

View File

@ -57,6 +57,14 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version);
#define CONTENT_LAVA 32
#define CONTENT_LAVASOURCE 33
// rays stuff
#define CONTENT_STONEBRICK 34
#define CONTENT_STEELSTONEBRICK 35
#define CONTENT_GLASSLIGHT 36
#define CONTENT_WOODJUNGLE 37
#define CONTENT_COALCHECKER 38
#define CONTENT_BRICKGREEN 39
// 0x800...0xfff (2048...4095): higher 4 bytes of param2 are not usable
#define CONTENT_GRASS 0x800 //1
#define CONTENT_TREE 0x801 //4
@ -64,7 +72,6 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version);
#define CONTENT_FARM_DIRT 0x803 //6
#define CONTENT_MESE 0x804 //7
#define CONTENT_MUD 0x805 //8
// used to be cloud
#define CONTENT_COTTON 0x806 //10
#define CONTENT_BORDERSTONE 0x807 //11
#define CONTENT_WOOD 0x808 //12
@ -87,5 +94,41 @@ MapNode mapnode_translate_to_internal(MapNode n_from, u8 version);
#define CONTENT_APPLE 0x819
#define CONTENT_SAPLING 0x820
// slabs
#define CONTENT_COBBLE_SLAB 0x821
#define CONTENT_MOSSYCOBBLE_SLAB 0x822
#define CONTENT_STONE_SLAB 0x823
#define CONTENT_WOOD_SLAB 0x824
#define CONTENT_JUNGLE_SLAB 0x825
#define CONTENT_BRICK_SLAB 0x826
#define CONTENT_SANDSTONE_SLAB 0x827
// stairs
#define CONTENT_COBBLE_STAIR 0x828
#define CONTENT_MOSSYCOBBLE_STAIR 0x829
#define CONTENT_STONE_STAIR 0x82a
#define CONTENT_WOOD_STAIR 0x82b
#define CONTENT_JUNGLE_STAIR 0x82c
#define CONTENT_BRICK_STAIR 0x82d
#define CONTENT_SANDSTONE_STAIR 0x82e
// upside down slabs
#define CONTENT_COBBLE_SLAB_UD 0x831
#define CONTENT_MOSSYCOBBLE_SLAB_UD 0x832
#define CONTENT_STONE_SLAB_UD 0x833
#define CONTENT_WOOD_SLAB_UD 0x834
#define CONTENT_JUNGLE_SLAB_UD 0x835
#define CONTENT_BRICK_SLAB_UD 0x836
#define CONTENT_SANDSTONE_SLAB_UD 0x837
// upside down stairs
#define CONTENT_COBBLE_STAIR_UD 0x838
#define CONTENT_MOSSYCOBBLE_STAIR_UD 0x839
#define CONTENT_STONE_STAIR_UD 0x83a
#define CONTENT_WOOD_STAIR_UD 0x83b
#define CONTENT_JUNGLE_STAIR_UD 0x83c
#define CONTENT_BRICK_STAIR_UD 0x83d
#define CONTENT_SANDSTONE_STAIR_UD 0x83e
#endif

View File

@ -158,8 +158,9 @@ void ItemSAO::step(float dtime, bool send_recommended)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
v3f accel_f = v3f(0,0,0);
moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
box, dtime, pos_f, m_speed_f);
box, 0.0, dtime, pos_f, m_speed_f, accel_f);
if(send_recommended == false)
return;
@ -390,8 +391,9 @@ void RatSAO::step(float dtime, bool send_recommended)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
v3f accel_f = v3f(0,0,0);
moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
box, dtime, pos_f, m_speed_f);
box, 0.0, dtime, pos_f, m_speed_f, accel_f);
// basicly 'die in lava'
if (moveresult.touching_lethal)
@ -630,8 +632,9 @@ void Oerkki1SAO::step(float dtime, bool send_recommended)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);*/
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
moveresult = collisionMovePrecise(&m_env->getMap(), pos_max_d,
box, dtime, pos_f, m_speed_f);
v3f accel_f = v3f(0,0,0);
moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
box, 0.0, dtime, pos_f, m_speed_f, accel_f);
if (moveresult.touching_lethal)
{
@ -877,8 +880,9 @@ void FireflySAO::step(float dtime, bool send_recommended)
m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
v3f pos_f = getBasePosition();
v3f pos_f_old = pos_f;
v3f accel_f = v3f(0,0,0);
moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
box, dtime, pos_f, m_speed_f);
box, 0.0, dtime, pos_f, m_speed_f, accel_f);
// basicly 'die in lava'
if (moveresult.touching_lethal)

View File

@ -39,6 +39,40 @@ ContentFeatures::~ContentFeatures()
#endif
}
static std::vector<aabb3f> transformNodeBox(const ContentFeatures &n,
const std::vector<aabb3f> &nodebox)
{
std::vector<aabb3f> boxes;
// TODO: facedir!
int facedir = 0;
for(std::vector<aabb3f>::const_iterator
i = nodebox.begin();
i != nodebox.end(); i++)
{
aabb3f box = *i;
if (facedir == 1) {
box.MinEdge.rotateXZBy(-90);
box.MaxEdge.rotateXZBy(-90);
box.repair();
}else if (facedir == 2) {
box.MinEdge.rotateXZBy(180);
box.MaxEdge.rotateXZBy(180);
box.repair();
}else if (facedir == 3) {
box.MinEdge.rotateXZBy(90);
box.MaxEdge.rotateXZBy(90);
box.repair();
}
boxes.push_back(box);
}
return boxes;
}
std::vector<aabb3f> ContentFeatures::getNodeBoxes() const
{
return transformNodeBox(*this, nodeboxes);
}
#ifndef SERVER
void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha)
{
@ -88,6 +122,46 @@ void ContentFeatures::setInventoryTextureCube(std::string top,
imgname_full += right;
inventory_texture = g_texturesource->getTextureRaw(imgname_full);
}
void ContentFeatures::setInventoryTextureSlab(std::string top,
std::string left, std::string right)
{
if(g_texturesource == NULL)
return;
str_replace_char(top, '^', '&');
str_replace_char(left, '^', '&');
str_replace_char(right, '^', '&');
std::string imgname_full;
imgname_full += "[inventoryslab{";
imgname_full += top;
imgname_full += "{";
imgname_full += left;
imgname_full += "{";
imgname_full += right;
inventory_texture = g_texturesource->getTextureRaw(imgname_full);
}
void ContentFeatures::setInventoryTextureStair(std::string top,
std::string left, std::string right)
{
if(g_texturesource == NULL)
return;
str_replace_char(top, '^', '&');
str_replace_char(left, '^', '&');
str_replace_char(right, '^', '&');
std::string imgname_full;
imgname_full += "[inventorystair{";
imgname_full += top;
imgname_full += "{";
imgname_full += left;
imgname_full += "{";
imgname_full += right;
inventory_texture = g_texturesource->getTextureRaw(imgname_full);
}
#endif
struct ContentFeatures g_content_features[MAX_CONTENT+1];

View File

@ -77,6 +77,26 @@ void init_mapnode();
//#define CONTENT_AIR 254
#define CONTENT_AIR 126
/*
Draw types
*/
enum ContentDrawType
{
CDT_AIRLIKE,
CDT_CUBELIKE,
CDT_RAILLIKE,
CDT_PLANTLIKE,
CDT_PLANTLIKE_SML,
CDT_PLANTLIKE_LGE,
CDT_LIQUID,
CDT_LIQUID_SOURCE,
CDT_SIGNLIKE,
CDT_NODEBOX,
CDT_GLASSLIKE,
CDT_TORCHLIKE,
CDT_FENCELIKE
};
/*
Content feature list
*/
@ -124,6 +144,7 @@ struct ContentFeatures
video::SMaterial *special_material2;
AtlasPointer *special_atlas;
#endif
std::vector<aabb3f> nodeboxes;
// List of all block textures that have been used (value is dummy)
// Exists on server too for cleaner code in content_mapnode.cpp
@ -131,6 +152,8 @@ struct ContentFeatures
// Type of MapNode::param1
ContentParamType param_type;
// drawtype
ContentDrawType draw_type;
// True for all ground-like things like stone and mud, false for eg. trees
bool is_ground_content;
bool light_propagates;
@ -202,8 +225,18 @@ struct ContentFeatures
special_material = NULL;
special_material2 = NULL;
special_atlas = NULL;
nodeboxes.clear();
nodeboxes.push_back(core::aabbox3d<f32>(
-0.5*BS,
-0.5*BS,
-0.5*BS,
0.5*BS,
0.5*BS,
0.5*BS
));
#endif
param_type = CPT_NONE;
draw_type = CDT_AIRLIKE;
is_ground_content = false;
light_propagates = false;
sunlight_propagates = false;
@ -235,6 +268,26 @@ struct ContentFeatures
~ContentFeatures();
/*
Bounding Box
*/
/*
Gets list of node boxes (used for collision)
*/
std::vector<aabb3f> getNodeBoxes() const;
void setNodeBox(core::aabbox3d<f32> bb)
{
nodeboxes.clear();
nodeboxes.push_back(bb);
}
void addNodeBox(core::aabbox3d<f32> bb)
{
nodeboxes.push_back(bb);
}
/*
Quickhands for simple materials
*/
@ -278,11 +331,21 @@ struct ContentFeatures
void setInventoryTextureCube(std::string top,
std::string left, std::string right)
{}
void setInventoryTextureSlab(std::string top,
std::string left, std::string right)
{}
void setInventoryTextureStair(std::string top,
std::string left, std::string right)
{}
#else
void setInventoryTexture(std::string imgname);
void setInventoryTextureCube(std::string top,
std::string left, std::string right);
void setInventoryTextureSlab(std::string top,
std::string left, std::string right);
void setInventoryTextureStair(std::string top,
std::string left, std::string right);
#endif
};

View File

@ -338,12 +338,11 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
/*
Calculate new position
*/
position += m_speed * dtime;
position += m_speed * dtime/2;
// Skip collision detection if a special movement mode is used
bool free_move = g_settings->getBool("free_move");
if(free_move)
{
if (free_move) {
setPosition(position);
return;
}
@ -360,20 +359,15 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
*/
try{
// If in water, the threshold of coming out is at higher y
if(in_water)
{
if (in_water) {
v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
in_water = content_liquid(map.getNode(pp).getContent());
}
// If not in water, the threshold of going in is at lower y
else
{
}else{
v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
in_water = content_liquid(map.getNode(pp).getContent());
}
}
catch(InvalidPositionException &e)
{
}catch(InvalidPositionException &e) {
in_water = false;
}
@ -383,9 +377,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
try{
v3s16 pp = floatToInt(position + v3f(0,0,0), BS);
in_water_stable = content_liquid(map.getNode(pp).getContent());
}
catch(InvalidPositionException &e)
{
}catch(InvalidPositionException &e) {
in_water_stable = false;
}
@ -393,14 +385,12 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
Check if player is climbing
*/
try {
try{
v3s16 pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
is_climbing = ((content_features(map.getNode(pp).getContent()).climbable ||
content_features(map.getNode(pp2).getContent()).climbable) && !free_move);
}
catch(InvalidPositionException &e)
{
}catch(InvalidPositionException &e) {
is_climbing = false;
}
@ -421,245 +411,78 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
// Maximum distance over border for sneaking
f32 sneak_max = BS*0.4;
/*
If sneaking, player has larger collision radius to keep from
falling
*/
/*if(control.sneak)
player_radius = sneak_max + d*1.1;*/
/*
If sneaking, keep in range from the last walked node and don't
fall off from it
*/
if(control.sneak && m_sneak_node_exists)
{
if (control.sneak && m_sneak_node_exists) {
f32 maxd = 0.5*BS + sneak_max;
v3f lwn_f = intToFloat(m_sneak_node, BS);
position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
f32 min_y = lwn_f.Y + 0.5*BS;
if(position.Y < min_y)
{
if (position.Y < min_y) {
position.Y = min_y;
//v3f old_speed = m_speed;
if(m_speed.Y < 0)
m_speed.Y = 0;
/*if(collision_info)
{
// Report fall collision
if(old_speed.Y < m_speed.Y - 0.1)
{
CollisionInfo info;
info.t = COLLISION_FALL;
info.speed = m_speed.Y - old_speed.Y;
collision_info->push_back(info);
}
}*/
}
}
/*
Calculate player collision box (new and old)
*/
core::aabbox3d<f32> playerbox(
position.X - player_radius,
position.Y - 0.0,
position.Z - player_radius,
position.X + player_radius,
position.Y + player_height,
position.Z + player_radius
);
core::aabbox3d<f32> playerbox_old(
oldpos.X - player_radius,
oldpos.Y - 0.0,
oldpos.Z - player_radius,
oldpos.X + player_radius,
oldpos.Y + player_height,
oldpos.Z + player_radius
-player_radius,
0.0,
-player_radius,
player_radius,
player_height,
player_radius
);
float player_stepheight = touching_ground ? (BS*0.6) : (BS*0.2);
v3f accel_f = v3f(0,0,0);
collisionMoveResult result = collisionMoveSimple(&map,
pos_max_d, playerbox,
player_stepheight, dtime,
position,
m_speed,
accel_f);
/*
If the player's feet touch the topside of any node, this is
set to true.
Player is allowed to jump when this is true.
*/
touching_ground = false;
/*std::cout<<"Checking collisions for ("
<<oldpos_i.X<<","<<oldpos_i.Y<<","<<oldpos_i.Z
<<") -> ("
<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z
<<"):"<<std::endl;*/
bool standing_on_unloaded = false;
/*
Go through every node around the player
*/
for(s16 y = oldpos_i.Y - 1; y <= oldpos_i.Y + 2; y++)
for(s16 z = oldpos_i.Z - 1; z <= oldpos_i.Z + 1; z++)
for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
{
bool is_unloaded = false;
try{
// Player collides into walkable nodes
if(content_walkable(map.getNode(v3s16(x,y,z)).getContent()) == false)
continue;
}
catch(InvalidPositionException &e)
{
is_unloaded = true;
// Doing nothing here will block the player from
// walking over map borders
}
core::aabbox3d<f32> nodebox = getNodeBox(v3s16(x,y,z), BS);
/*
See if the player is touching ground.
Player touches ground if player's minimum Y is near node's
maximum Y and player's X-Z-area overlaps with the node's
X-Z-area.
Use 0.15*BS so that it is easier to get on a node.
*/
if(
//fabs(nodebox.MaxEdge.Y-playerbox.MinEdge.Y) < d
fabs(nodebox.MaxEdge.Y-playerbox.MinEdge.Y) < 0.15*BS
&& nodebox.MaxEdge.X-d > playerbox.MinEdge.X
&& nodebox.MinEdge.X+d < playerbox.MaxEdge.X
&& nodebox.MaxEdge.Z-d > playerbox.MinEdge.Z
&& nodebox.MinEdge.Z+d < playerbox.MaxEdge.Z
){
touching_ground = true;
if(is_unloaded)
standing_on_unloaded = true;
}
// If player doesn't intersect with node, ignore node.
if(playerbox.intersectsWithBox(nodebox) == false)
continue;
/*
Go through every axis
*/
v3f dirs[3] = {
v3f(0,0,1), // back-front
v3f(0,1,0), // top-bottom
v3f(1,0,0), // right-left
};
for(u16 i=0; i<3; i++)
{
/*
Calculate values along the axis
*/
f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[i]);
f32 nodemin = nodebox.MinEdge.dotProduct(dirs[i]);
f32 playermax = playerbox.MaxEdge.dotProduct(dirs[i]);
f32 playermin = playerbox.MinEdge.dotProduct(dirs[i]);
f32 playermax_old = playerbox_old.MaxEdge.dotProduct(dirs[i]);
f32 playermin_old = playerbox_old.MinEdge.dotProduct(dirs[i]);
/*
Check collision for the axis.
Collision happens when player is going through a surface.
*/
/*f32 neg_d = d;
f32 pos_d = d;
// Make it easier to get on top of a node
if(i == 1)
neg_d = 0.15*BS;
bool negative_axis_collides =
(nodemax > playermin && nodemax <= playermin_old + neg_d
&& m_speed.dotProduct(dirs[i]) < 0);
bool positive_axis_collides =
(nodemin < playermax && nodemin >= playermax_old - pos_d
&& m_speed.dotProduct(dirs[i]) > 0);*/
bool negative_axis_collides =
(nodemax > playermin && nodemax <= playermin_old + d
&& m_speed.dotProduct(dirs[i]) < 0);
bool positive_axis_collides =
(nodemin < playermax && nodemin >= playermax_old - d
&& m_speed.dotProduct(dirs[i]) > 0);
bool main_axis_collides =
negative_axis_collides || positive_axis_collides;
/*
Check overlap of player and node in other axes
*/
bool other_axes_overlap = true;
for(u16 j=0; j<3; j++)
{
if(j == i)
continue;
f32 nodemax = nodebox.MaxEdge.dotProduct(dirs[j]);
f32 nodemin = nodebox.MinEdge.dotProduct(dirs[j]);
f32 playermax = playerbox.MaxEdge.dotProduct(dirs[j]);
f32 playermin = playerbox.MinEdge.dotProduct(dirs[j]);
if(!(nodemax - d > playermin && nodemin + d < playermax))
{
other_axes_overlap = false;
break;
}
}
/*
If this is a collision, revert the position in the main
direction.
*/
if(other_axes_overlap && main_axis_collides)
{
//v3f old_speed = m_speed;
m_speed -= m_speed.dotProduct(dirs[i]) * dirs[i];
position -= position.dotProduct(dirs[i]) * dirs[i];
position += oldpos.dotProduct(dirs[i]) * dirs[i];
/*if(collision_info)
{
// Report fall collision
if(old_speed.Y < m_speed.Y - 0.1)
{
CollisionInfo info;
info.t = COLLISION_FALL;
info.speed = m_speed.Y - old_speed.Y;
collision_info->push_back(info);
}
}*/
}
}
} // xyz
touching_ground = result.touching_ground;
/*
Check the nodes under the player to see from which node the
player is sneaking from, if any.
player is sneaking from, if any. If the node from under
the player has been removed, the player falls.
*/
{
v3s16 current_node = floatToInt(position - v3f(0,BS/2,0), BS);
if (m_sneak_node_exists && map.getNodeNoEx(m_old_node_below).getContent() == CONTENT_AIR && m_old_node_below_type != CONTENT_AIR) {
// Old node appears to have been removed; that is,
// it wasn't air before but now it is
m_refresh_sneak_node = false;
m_sneak_node_exists = false;
}else if (map.getNodeNoEx(current_node).getContent() != CONTENT_AIR) {
// We are on something, so make sure to recalculate the sneak
// node.
m_refresh_sneak_node = true;
}
if (m_refresh_sneak_node) {
v3s16 pos_i_bottom = floatToInt(position - v3f(0,BS/2,0), BS);
v2f player_p2df(position.X, position.Z);
f32 min_distance_f = 100000.0*BS;
// If already seeking from some node, compare to it.
/*if(m_sneak_node_exists)
{
v3f sneaknode_pf = intToFloat(m_sneak_node, BS);
v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z);
f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df);
f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y);
// Ignore if player is not on the same level (likely dropped)
if(d_vert_f < 0.15*BS)
min_distance_f = d_horiz_f;
}*/
v3s16 new_sneak_node = m_sneak_node;
for(s16 x=-1; x<=1; x++)
for(s16 z=-1; z<=1; z++)
for (s16 x=-1; x<=1; x++)
for (s16 z=-1; z<=1; z++)
{
v3s16 p = pos_i_bottom + v3s16(x,0,z);
v3f pf = intToFloat(p, BS);
@ -669,20 +492,17 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
fabs(player_p2df.X-node_p2df.X),
fabs(player_p2df.Y-node_p2df.Y));
if(distance_f > min_distance_f ||
max_axis_distance_f > 0.5*BS + sneak_max + 0.1*BS)
if (distance_f > min_distance_f || max_axis_distance_f > 0.5*BS + sneak_max + 0.1*BS)
continue;
try{
// The node to be sneaked on has to be walkable
if(content_walkable(map.getNode(p).getContent()) == false)
if (content_features(map.getNode(p).getContent()).walkable == false)
continue;
// And the node above it has to be nonwalkable
if(content_walkable(map.getNode(p+v3s16(0,1,0)).getContent()) == true)
if (content_features(map.getNode(p+v3s16(0,1,0)).getContent()).walkable == true)
continue;
}
catch(InvalidPositionException &e)
{
}catch(InvalidPositionException &e) {
continue;
}
@ -692,22 +512,14 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
bool sneak_node_found = (min_distance_f < 100000.0*BS*0.9);
if(control.sneak && m_sneak_node_exists)
{
if(sneak_node_found)
m_sneak_node = new_sneak_node;
}
else
{
m_sneak_node = new_sneak_node;
m_sneak_node_exists = sneak_node_found;
}
/*
If sneaking, the player's collision box can be in air, so
this has to be set explicitly
*/
if(sneak_node_found && control.sneak)
if (sneak_node_found && control.sneak)
touching_ground = true;
}
@ -722,7 +534,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
if(collision_info)
{
// Report fall collision
if(old_speed.Y < m_speed.Y - 0.1 && !standing_on_unloaded)
if(old_speed.Y < m_speed.Y - 0.1 && !result.standing_on_unloaded)
{
CollisionInfo info;
info.t = COLLISION_FALL;

View File

@ -367,8 +367,12 @@ public:
private:
// This is used for determining the sneaking range
v3s16 m_sneak_node;
bool m_refresh_sneak_node;
// Whether the player is allowed to sneak
bool m_sneak_node_exists;
v3s16 m_old_node_below;
content_t m_old_node_below_type;
};
#endif // !SERVER

View File

@ -1349,6 +1349,233 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
image->drop();
}
}
/*
[inventoryslab{topimage{leftimage{rightimage
In every subimage, replace ^ with &.
Create an "inventory slab".
NOTE: This should be used only on its own.
Example (a grass slab (not actually used in game):
"[inventoryslab{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
*/
else if(part_of_name.substr(0,14) == "[inventoryslab")
{
if(baseimg != NULL)
{
errorstream<<"generate_image(): baseimg!=NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
}
str_replace_char(part_of_name, '&', '^');
Strfnd sf(part_of_name);
sf.next("{");
std::string imagename_top = sf.next("{");
std::string imagename_left = sf.next("{");
std::string imagename_right = sf.next("{");
// Generate images for the faces of the cube
video::IImage *img_top = generate_image_from_scratch(
imagename_top, device);
video::IImage *img_left = generate_image_from_scratch(
imagename_left, device);
video::IImage *img_right = generate_image_from_scratch(
imagename_right, device);
assert(img_top && img_left && img_right);
// Create textures from images
video::ITexture *texture_top = driver->addTexture(
(imagename_top + "__temp__").c_str(), img_top);
video::ITexture *texture_left = driver->addTexture(
(imagename_left + "__temp__").c_str(), img_left);
video::ITexture *texture_right = driver->addTexture(
(imagename_right + "__temp__").c_str(), img_right);
assert(texture_top && texture_left && texture_right);
// Drop images
img_top->drop();
img_left->drop();
img_right->drop();
/*
Draw a cube mesh into a render target texture
*/
scene::IMesh* cube = createCubeMesh(v3f(1, 0.5, 1));
setMeshColor(cube, video::SColor(255, 255, 255, 255));
cube->getMeshBuffer(0)->getMaterial().setTexture(0, texture_top);
cube->getMeshBuffer(1)->getMaterial().setTexture(0, texture_top);
cube->getMeshBuffer(2)->getMaterial().setTexture(0, texture_right);
cube->getMeshBuffer(3)->getMaterial().setTexture(0, texture_right);
cube->getMeshBuffer(4)->getMaterial().setTexture(0, texture_left);
cube->getMeshBuffer(5)->getMaterial().setTexture(0, texture_left);
core::dimension2d<u32> dim(64,64);
std::string rtt_texture_name = part_of_name + "_RTT";
v3f camera_position(0, 1.0, -1.5);
camera_position.rotateXZBy(45);
v3f camera_lookat(0, 0, 0);
core::CMatrix4<f32> camera_projection_matrix;
// Set orthogonal projection
camera_projection_matrix.buildProjectionMatrixOrthoLH(
1.65, 1.65, 0, 100);
video::SColorf ambient_light(0.2,0.2,0.2);
v3f light_position(10, 100, -50);
video::SColorf light_color(0.5,0.5,0.5);
f32 light_radius = 1000;
video::ITexture *rtt = generateTextureFromMesh(
cube, device, dim, rtt_texture_name,
camera_position,
camera_lookat,
camera_projection_matrix,
ambient_light,
light_position,
light_color,
light_radius);
// Drop mesh
cube->drop();
// Free textures of images
driver->removeTexture(texture_top);
driver->removeTexture(texture_left);
driver->removeTexture(texture_right);
if(rtt == NULL)
{
baseimg = generate_image_from_scratch(
imagename_top, device);
return true;
}
// Create image of render target
video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
assert(image);
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
if(image)
{
image->copyTo(baseimg);
image->drop();
}
}
/*
[inventorystair{topimage{leftimage{rightimage
In every subimage, replace ^ with &.
Create an "inventory stair".
NOTE: This should be used only on its own.
Example (a grass stair (not actually used in game):
"[inventorystair{grass.png{mud.png&grass_side.png{mud.png&grass_side.png"
TODO: not implemented, only creates a cube
*/
else if(part_of_name.substr(0,15) == "[inventorystair")
{
if(baseimg != NULL)
{
errorstream<<"generate_image(): baseimg!=NULL "
<<"for part_of_name=\""<<part_of_name
<<"\", cancelling."<<std::endl;
return false;
}
str_replace_char(part_of_name, '&', '^');
Strfnd sf(part_of_name);
sf.next("{");
std::string imagename_top = sf.next("{");
std::string imagename_left = sf.next("{");
std::string imagename_right = sf.next("{");
// Generate images for the faces of the cube
video::IImage *img_top = generate_image_from_scratch(
imagename_top, device);
video::IImage *img_left = generate_image_from_scratch(
imagename_left, device);
video::IImage *img_right = generate_image_from_scratch(
imagename_right, device);
assert(img_top && img_left && img_right);
// Create textures from images
video::ITexture *texture_top = driver->addTexture(
(imagename_top + "__temp__").c_str(), img_top);
video::ITexture *texture_left = driver->addTexture(
(imagename_left + "__temp__").c_str(), img_left);
video::ITexture *texture_right = driver->addTexture(
(imagename_right + "__temp__").c_str(), img_right);
assert(texture_top && texture_left && texture_right);
// Drop images
img_top->drop();
img_left->drop();
img_right->drop();
/*
Draw a cube mesh into a render target texture
*/
scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1));
setMeshColor(cube, video::SColor(255, 255, 255, 255));
cube->getMeshBuffer(0)->getMaterial().setTexture(0, texture_top);
cube->getMeshBuffer(1)->getMaterial().setTexture(0, texture_top);
cube->getMeshBuffer(2)->getMaterial().setTexture(0, texture_right);
cube->getMeshBuffer(3)->getMaterial().setTexture(0, texture_right);
cube->getMeshBuffer(4)->getMaterial().setTexture(0, texture_left);
cube->getMeshBuffer(5)->getMaterial().setTexture(0, texture_left);
core::dimension2d<u32> dim(64,64);
std::string rtt_texture_name = part_of_name + "_RTT";
v3f camera_position(0, 1.0, -1.5);
camera_position.rotateXZBy(45);
v3f camera_lookat(0, 0, 0);
core::CMatrix4<f32> camera_projection_matrix;
// Set orthogonal projection
camera_projection_matrix.buildProjectionMatrixOrthoLH(
1.65, 1.65, 0, 100);
video::SColorf ambient_light(0.2,0.2,0.2);
v3f light_position(10, 100, -50);
video::SColorf light_color(0.5,0.5,0.5);
f32 light_radius = 1000;
video::ITexture *rtt = generateTextureFromMesh(
cube, device, dim, rtt_texture_name,
camera_position,
camera_lookat,
camera_projection_matrix,
ambient_light,
light_position,
light_color,
light_radius);
// Drop mesh
cube->drop();
// Free textures of images
driver->removeTexture(texture_top);
driver->removeTexture(texture_left);
driver->removeTexture(texture_right);
if(rtt == NULL)
{
baseimg = generate_image_from_scratch(
imagename_top, device);
return true;
}
// Create image of render target
video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
assert(image);
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
if(image)
{
image->copyTo(baseimg);
image->drop();
}
}
else
{
infostream<<"generate_image(): Invalid "