Merge branch 'view_bobbing_and_vielded_tool'

This commit is contained in:
Perttu Ahola 2011-09-26 15:10:02 +03:00
commit 061d4b4202
23 changed files with 1417 additions and 501 deletions

@ -142,6 +142,7 @@ set(minetest_SRCS
mapblock_mesh.cpp
farmesh.cpp
keycode.cpp
camera.cpp
clouds.cpp
clientobject.cpp
guiMainMenu.cpp

898
src/camera.cpp Normal file

@ -0,0 +1,898 @@
/*
Minetest-c55
Copyright (C) 2010-2011 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
(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.
You should have received a copy of the GNU 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.
*/
#include "camera.h"
#include "debug.h"
#include "client.h"
#include "main.h" // for g_settings
#include "map.h"
#include "player.h"
#include "tile.h"
#include <cmath>
Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
m_smgr(smgr),
m_playernode(NULL),
m_headnode(NULL),
m_cameranode(NULL),
m_wieldmgr(NULL),
m_wieldnode(NULL),
m_draw_control(draw_control),
m_viewing_range_min(5.0),
m_viewing_range_max(5.0),
m_camera_position(0,0,0),
m_camera_direction(0,0,0),
m_aspect(1.0),
m_fov_x(1.0),
m_fov_y(1.0),
m_wanted_frametime(0.0),
m_added_frametime(0),
m_added_frames(0),
m_range_old(0),
m_frametime_old(0),
m_frametime_counter(0),
m_time_per_range(30. / 50), // a sane default of 30ms per 50 nodes of range
m_view_bobbing_anim(0),
m_view_bobbing_state(0),
m_view_bobbing_speed(0),
m_digging_anim(0),
m_digging_button(-1)
{
//dstream<<__FUNCTION_NAME<<std::endl;
// note: making the camera node a child of the player node
// would lead to unexpected behaviour, so we don't do that.
m_playernode = smgr->addEmptySceneNode(smgr->getRootSceneNode());
m_headnode = smgr->addEmptySceneNode(m_playernode);
m_cameranode = smgr->addCameraSceneNode(smgr->getRootSceneNode());
m_cameranode->bindTargetAndRotation(true);
// This needs to be in its own scene manager. It is drawn after
// all other 3D scene nodes and before the GUI.
m_wieldmgr = smgr->createNewSceneManager();
m_wieldmgr->addCameraSceneNode();
m_wieldnode = new ExtrudedSpriteSceneNode(m_wieldmgr->getRootSceneNode(), m_wieldmgr);
updateSettings();
}
Camera::~Camera()
{
m_wieldmgr->drop();
m_wieldnode->drop();
}
bool Camera::successfullyCreated(std::wstring& error_message)
{
if (m_playernode == NULL)
{
error_message = L"Failed to create the player scene node";
return false;
}
if (m_headnode == NULL)
{
error_message = L"Failed to create the head scene node";
return false;
}
if (m_cameranode == NULL)
{
error_message = L"Failed to create the camera scene node";
return false;
}
if (m_wieldmgr == NULL)
{
error_message = L"Failed to create the wielded item scene manager";
return false;
}
if (m_wieldnode == NULL)
{
error_message = L"Failed to create the wielded item scene node";
return false;
}
return true;
}
// Returns the fractional part of x
inline f32 my_modf(f32 x)
{
double dummy;
return modf(x, &dummy);
}
void Camera::step(f32 dtime)
{
if (m_view_bobbing_state != 0)
{
//f32 offset = dtime * m_view_bobbing_speed * 0.035;
f32 offset = dtime * m_view_bobbing_speed * 0.030;
if (m_view_bobbing_state == 2)
{
#if 0
// Animation is getting turned off
if (m_view_bobbing_anim < 0.5)
m_view_bobbing_anim -= offset;
else
m_view_bobbing_anim += offset;
if (m_view_bobbing_anim <= 0 || m_view_bobbing_anim >= 1)
{
m_view_bobbing_anim = 0;
m_view_bobbing_state = 0;
}
#endif
#if 1
// Animation is getting turned off
if(m_view_bobbing_anim < 0.25){
m_view_bobbing_anim -= offset;
} else if(m_view_bobbing_anim > 0.75){
m_view_bobbing_anim += offset;
} if(m_view_bobbing_anim < 0.5){
m_view_bobbing_anim += offset;
if(m_view_bobbing_anim > 0.5)
m_view_bobbing_anim = 0.5;
} else {
m_view_bobbing_anim -= offset;
if(m_view_bobbing_anim < 0.5)
m_view_bobbing_anim = 0.5;
}
if(m_view_bobbing_anim <= 0 || m_view_bobbing_anim >= 1 ||
fabs(m_view_bobbing_anim - 0.5) < 0.01)
{
m_view_bobbing_anim = 0;
m_view_bobbing_state = 0;
}
#endif
}
else
{
m_view_bobbing_anim = my_modf(m_view_bobbing_anim + offset);
}
}
if (m_digging_button != -1)
{
f32 offset = dtime * 3.5;
m_digging_anim += offset;
if (m_digging_anim >= 1)
{
m_digging_anim = 0;
m_digging_button = -1;
}
}
}
void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
{
// Set player node transformation
m_playernode->setPosition(player->getPosition());
m_playernode->setRotation(v3f(0, -1 * player->getYaw(), 0));
m_playernode->updateAbsolutePosition();
// Set head node transformation
m_headnode->setPosition(player->getEyeOffset());
m_headnode->setRotation(v3f(player->getPitch(), 0, 0));
m_headnode->updateAbsolutePosition();
// Compute relative camera position and target
v3f rel_cam_pos = v3f(0,0,0);
v3f rel_cam_target = v3f(0,0,1);
v3f rel_cam_up = v3f(0,1,0);
if (m_view_bobbing_anim != 0)
{
f32 bobfrac = my_modf(m_view_bobbing_anim * 2);
f32 bobdir = (m_view_bobbing_anim < 0.5) ? 1.0 : -1.0;
#if 1
f32 bobknob = 1.2;
f32 bobtmp = sin(pow(bobfrac, bobknob) * PI);
f32 bobtmp2 = cos(pow(bobfrac, bobknob) * PI);
v3f bobvec = v3f(
0.3 * bobdir * sin(bobfrac * PI),
-0.28 * bobtmp * bobtmp,
0.);
//rel_cam_pos += 0.2 * bobvec;
//rel_cam_target += 0.03 * bobvec;
//rel_cam_up.rotateXYBy(0.02 * bobdir * bobtmp * PI);
float f = 1.0;
rel_cam_pos += bobvec * f;
//rel_cam_target += 0.995 * bobvec * f;
rel_cam_target += bobvec * f;
rel_cam_target.Z -= 0.005 * bobvec.Z * f;
//rel_cam_target.X -= 0.005 * bobvec.X * f;
//rel_cam_target.Y -= 0.005 * bobvec.Y * f;
rel_cam_up.rotateXYBy(-0.03 * bobdir * bobtmp * PI * f);
#else
f32 angle_deg = 1 * bobdir * sin(bobfrac * PI);
f32 angle_rad = angle_deg * PI / 180;
f32 r = 0.05;
v3f off = v3f(
r * sin(angle_rad),
r * (cos(angle_rad) - 1),
0);
rel_cam_pos += off;
//rel_cam_target += off;
rel_cam_up.rotateXYBy(angle_deg);
#endif
}
// Compute absolute camera position and target
m_headnode->getAbsoluteTransformation().transformVect(m_camera_position, rel_cam_pos);
m_headnode->getAbsoluteTransformation().rotateVect(m_camera_direction, rel_cam_target - rel_cam_pos);
v3f abs_cam_up;
m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up);
// Set camera node transformation
m_cameranode->setPosition(m_camera_position);
m_cameranode->setUpVector(abs_cam_up);
// *100.0 helps in large map coordinates
m_cameranode->setTarget(m_camera_position + 100 * m_camera_direction);
// FOV and and aspect ratio
m_aspect = (f32)screensize.X / (f32) screensize.Y;
m_fov_x = 2 * atan(0.5 * m_aspect * tan(m_fov_y));
m_cameranode->setAspectRatio(m_aspect);
m_cameranode->setFOV(m_fov_y);
// Just so big a value that everything rendered is visible
// Some more allowance that m_viewing_range_max * BS because of active objects etc.
m_cameranode->setFarValue(m_viewing_range_max * BS * 10);
// Position the wielded item
v3f wield_position = v3f(45, -35, 65);
v3f wield_rotation = v3f(90, -90, -90);
if (m_digging_button != -1)
{
f32 digfrac = m_digging_anim;
wield_position.X -= 30 * sin(pow(digfrac, 0.8f) * PI);
wield_position.Y += 15 * sin(digfrac * 2 * PI);
wield_position.Z += 5 * digfrac;
// Euler angles are PURE EVIL, so why not use quaternions?
core::quaternion quat_begin(wield_rotation * core::DEGTORAD);
core::quaternion quat_end(v3f(90, -10, -130) * core::DEGTORAD);
core::quaternion quat_slerp;
quat_slerp.slerp(quat_begin, quat_end, sin(digfrac * PI));
quat_slerp.toEuler(wield_rotation);
wield_rotation *= core::RADTODEG;
}
else {
f32 bobfrac = my_modf(m_view_bobbing_anim);
wield_position.X -= sin(bobfrac*PI*2.0) * 3.0;
wield_position.Y += sin(my_modf(bobfrac*2.0)*PI) * 3.0;
}
m_wieldnode->setPosition(wield_position);
m_wieldnode->setRotation(wield_rotation);
m_wieldnode->updateLight(player->light);
// Render distance feedback loop
updateViewingRange(frametime);
// If the player seems to be walking on solid ground,
// view bobbing is enabled and free_move is off,
// start (or continue) the view bobbing animation.
v3f speed = player->getSpeed();
if ((hypot(speed.X, speed.Z) > BS) &&
(player->touching_ground) &&
(g_settings.getBool("view_bobbing") == true) &&
(g_settings.getBool("free_move") == false))
{
// Start animation
m_view_bobbing_state = 1;
m_view_bobbing_speed = MYMIN(speed.getLength(), 40);
}
else if (m_view_bobbing_state == 1)
{
// Stop animation
m_view_bobbing_state = 2;
m_view_bobbing_speed = 60;
}
}
void Camera::updateViewingRange(f32 frametime_in)
{
if (m_draw_control.range_all)
return;
m_added_frametime += frametime_in;
m_added_frames += 1;
// Actually this counter kind of sucks because frametime is busytime
m_frametime_counter -= frametime_in;
if (m_frametime_counter > 0)
return;
m_frametime_counter = 0.2;
/*dstream<<__FUNCTION_NAME
<<": Collected "<<m_added_frames<<" frames, total of "
<<m_added_frametime<<"s."<<std::endl;
dstream<<"m_draw_control.blocks_drawn="
<<m_draw_control.blocks_drawn
<<", m_draw_control.blocks_would_have_drawn="
<<m_draw_control.blocks_would_have_drawn
<<std::endl;*/
m_draw_control.wanted_min_range = m_viewing_range_min;
m_draw_control.wanted_max_blocks = (1.5*m_draw_control.blocks_would_have_drawn)+1;
if (m_draw_control.wanted_max_blocks < 10)
m_draw_control.wanted_max_blocks = 10;
f32 block_draw_ratio = 1.0;
if (m_draw_control.blocks_would_have_drawn != 0)
{
block_draw_ratio = (f32)m_draw_control.blocks_drawn
/ (f32)m_draw_control.blocks_would_have_drawn;
}
// Calculate the average frametime in the case that all wanted
// blocks had been drawn
f32 frametime = m_added_frametime / m_added_frames / block_draw_ratio;
m_added_frametime = 0.0;
m_added_frames = 0;
f32 wanted_frametime_change = m_wanted_frametime - frametime;
//dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
// If needed frametime change is small, just return
if (fabs(wanted_frametime_change) < m_wanted_frametime*0.4)
{
//dstream<<"ignoring small wanted_frametime_change"<<std::endl;
return;
}
f32 range = m_draw_control.wanted_range;
f32 new_range = range;
f32 d_range = range - m_range_old;
f32 d_frametime = frametime - m_frametime_old;
if (d_range != 0)
{
m_time_per_range = d_frametime / d_range;
}
// The minimum allowed calculated frametime-range derivative:
// Practically this sets the maximum speed of changing the range.
// The lower this value, the higher the maximum changing speed.
// A low value here results in wobbly range (0.001)
// A high value here results in slow changing range (0.0025)
// SUGG: This could be dynamically adjusted so that when
// the camera is turning, this is lower
//f32 min_time_per_range = 0.0015;
f32 min_time_per_range = 0.0010;
//f32 min_time_per_range = 0.05 / range;
if(m_time_per_range < min_time_per_range)
{
m_time_per_range = min_time_per_range;
//dstream<<"m_time_per_range="<<m_time_per_range<<" (min)"<<std::endl;
}
else
{
//dstream<<"m_time_per_range="<<m_time_per_range<<std::endl;
}
f32 wanted_range_change = wanted_frametime_change / m_time_per_range;
// Dampen the change a bit to kill oscillations
//wanted_range_change *= 0.9;
//wanted_range_change *= 0.75;
wanted_range_change *= 0.5;
//dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;
// If needed range change is very small, just return
if(fabs(wanted_range_change) < 0.001)
{
//dstream<<"ignoring small wanted_range_change"<<std::endl;
return;
}
new_range += wanted_range_change;
//f32 new_range_unclamped = new_range;
new_range = MYMAX(new_range, m_viewing_range_min);
new_range = MYMIN(new_range, m_viewing_range_max);
/*dstream<<"new_range="<<new_range_unclamped
<<", clamped to "<<new_range<<std::endl;*/
m_draw_control.wanted_range = new_range;
m_range_old = new_range;
m_frametime_old = frametime;
}
void Camera::updateSettings()
{
m_viewing_range_min = g_settings.getS16("viewing_range_nodes_min");
m_viewing_range_min = MYMAX(5.0, m_viewing_range_min);
m_viewing_range_max = g_settings.getS16("viewing_range_nodes_max");
m_viewing_range_max = MYMAX(m_viewing_range_min, m_viewing_range_max);
f32 fov_degrees = g_settings.getFloat("fov");
fov_degrees = MYMAX(fov_degrees, 10.0);
fov_degrees = MYMIN(fov_degrees, 170.0);
m_fov_y = fov_degrees * PI / 180.0;
f32 wanted_fps = g_settings.getFloat("wanted_fps");
wanted_fps = MYMAX(wanted_fps, 1.0);
m_wanted_frametime = 1.0 / wanted_fps;
}
void Camera::wield(const InventoryItem* item)
{
if (item != NULL)
{
bool isCube = false;
// Try to make a MaterialItem cube.
if (std::string(item->getName()) == "MaterialItem")
{
// A block-type material
MaterialItem* mat_item = (MaterialItem*) item;
content_t content = mat_item->getMaterial();
if (content_features(content).solidness || content_features(content).visual_solidness)
{
m_wieldnode->setCube(content_features(content).tiles);
m_wieldnode->setScale(v3f(30));
isCube = true;
}
}
// If that failed, make an extruded sprite.
if (!isCube)
{
m_wieldnode->setSprite(item->getImageRaw());
m_wieldnode->setScale(v3f(40));
}
m_wieldnode->setVisible(true);
}
else
{
// Bare hands
m_wieldnode->setVisible(false);
}
}
void Camera::setDigging(s32 button)
{
if (m_digging_button == -1)
m_digging_button = button;
}
void Camera::drawWieldedTool()
{
m_wieldmgr->getVideoDriver()->clearZBuffer();
scene::ICameraSceneNode* cam = m_wieldmgr->getActiveCamera();
cam->setAspectRatio(m_cameranode->getAspectRatio());
cam->setFOV(m_cameranode->getFOV());
cam->setNearValue(0.1);
cam->setFarValue(100);
m_wieldmgr->drawAll();
}
ExtrudedSpriteSceneNode::ExtrudedSpriteSceneNode(
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id,
const v3f& position,
const v3f& rotation,
const v3f& scale
):
ISceneNode(parent, mgr, id, position, rotation, scale)
{
m_meshnode = mgr->addMeshSceneNode(NULL, this, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true);
m_thickness = 0.1;
m_cubemesh = NULL;
m_is_cube = false;
m_light = LIGHT_MAX;
}
ExtrudedSpriteSceneNode::~ExtrudedSpriteSceneNode()
{
removeChild(m_meshnode);
if (m_cubemesh)
m_cubemesh->drop();
}
void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture)
{
if (texture == NULL)
{
m_meshnode->setVisible(false);
return;
}
io::path name = getExtrudedName(texture);
scene::IMeshCache* cache = SceneManager->getMeshCache();
scene::IAnimatedMesh* mesh = cache->getMeshByName(name);
if (mesh != NULL)
{
// Extruded texture has been found in cache.
m_meshnode->setMesh(mesh);
}
else
{
// Texture was not yet extruded, do it now and save in cache
mesh = extrude(texture);
if (mesh == NULL)
{
dstream << "Warning: failed to extrude sprite" << std::endl;
m_meshnode->setVisible(false);
return;
}
cache->addMesh(name, mesh);
m_meshnode->setMesh(mesh);
mesh->drop();
}
m_meshnode->setScale(v3f(1, 1, m_thickness));
m_meshnode->getMaterial(0).setTexture(0, texture);
m_meshnode->getMaterial(0).setFlag(video::EMF_LIGHTING, false);
m_meshnode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, false);
m_meshnode->getMaterial(0).MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
m_meshnode->setVisible(true);
m_is_cube = false;
updateLight(m_light);
}
void ExtrudedSpriteSceneNode::setCube(const TileSpec tiles[6])
{
if (m_cubemesh == NULL)
m_cubemesh = createCubeMesh();
m_meshnode->setMesh(m_cubemesh);
m_meshnode->setScale(v3f(1));
for (int i = 0; i < 6; ++i)
{
// Get the tile texture and atlas transformation
video::ITexture* atlas = tiles[i].texture.atlas;
v2f pos = tiles[i].texture.pos;
v2f size = tiles[i].texture.size;
// Set material flags and texture
video::SMaterial& material = m_meshnode->getMaterial(i);
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
tiles[i].applyMaterialOptions(material);
material.setTexture(0, atlas);
material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
}
m_meshnode->setVisible(true);
m_is_cube = true;
updateLight(m_light);
}
void ExtrudedSpriteSceneNode::updateLight(u8 light)
{
m_light = light;
u8 li = decode_light(light);
// Set brightness one lower than incoming light
diminish_light(li);
video::SColor color(255,li,li,li);
setMeshVerticesColor(m_meshnode->getMesh(), color);
}
void ExtrudedSpriteSceneNode::removeSpriteFromCache(video::ITexture* texture)
{
scene::IMeshCache* cache = SceneManager->getMeshCache();
scene::IAnimatedMesh* mesh = cache->getMeshByName(getExtrudedName(texture));
if (mesh != NULL)
cache->removeMesh(mesh);
}
void ExtrudedSpriteSceneNode::setSpriteThickness(f32 thickness)
{
m_thickness = thickness;
if (!m_is_cube)
m_meshnode->setScale(v3f(1, 1, thickness));
}
const core::aabbox3d<f32>& ExtrudedSpriteSceneNode::getBoundingBox() const
{
return m_meshnode->getBoundingBox();
}
void ExtrudedSpriteSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
void ExtrudedSpriteSceneNode::render()
{
// do nothing
}
io::path ExtrudedSpriteSceneNode::getExtrudedName(video::ITexture* texture)
{
io::path path = texture->getName();
path.append("/[extruded]");
return path;
}
scene::IAnimatedMesh* ExtrudedSpriteSceneNode::extrudeARGB(u32 width, u32 height, u8* data)
{
const s32 argb_wstep = 4 * width;
const s32 alpha_threshold = 1;
scene::IMeshBuffer* buf = new scene::SMeshBuffer();
video::SColor c(255,255,255,255);
// Front and back
{
video::S3DVertex vertices[8] =
{
video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
video::S3DVertex(+0.5,-0.5,+0.5, 0,0,+1, c, 1,1),
video::S3DVertex(+0.5,+0.5,+0.5, 0,0,+1, c, 1,0),
video::S3DVertex(-0.5,+0.5,+0.5, 0,0,+1, c, 0,0),
video::S3DVertex(-0.5,-0.5,+0.5, 0,0,+1, c, 0,1),
};
u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
buf->append(vertices, 8, indices, 12);
}
// "Interior"
// (add faces where a solid pixel is next to a transparent one)
u8* solidity = new u8[(width+2) * (height+2)];
u32 wstep = width + 2;
for (u32 y = 0; y < height + 2; ++y)
{
u8* scanline = solidity + y * wstep;
if (y == 0 || y == height + 1)
{
for (u32 x = 0; x < width + 2; ++x)
scanline[x] = 0;
}
else
{
scanline[0] = 0;
u8* argb_scanline = data + (y - 1) * argb_wstep;
for (u32 x = 0; x < width; ++x)
scanline[x+1] = (argb_scanline[x*4+3] >= alpha_threshold);
scanline[width + 1] = 0;
}
}
// without this, there would be occasional "holes" in the mesh
f32 eps = 0.01;
for (u32 y = 0; y <= height; ++y)
{
u8* scanline = solidity + y * wstep + 1;
for (u32 x = 0; x <= width; ++x)
{
if (scanline[x] && !scanline[x + wstep])
{
u32 xx = x + 1;
while (scanline[xx] && !scanline[xx + wstep])
++xx;
f32 vx1 = (x - eps) / (f32) width - 0.5;
f32 vx2 = (xx + eps) / (f32) width - 0.5;
f32 vy = 0.5 - (y - eps) / (f32) height;
f32 tx1 = x / (f32) width;
f32 tx2 = xx / (f32) width;
f32 ty = (y - 0.5) / (f32) height;
video::S3DVertex vertices[8] =
{
video::S3DVertex(vx1,vy,-0.5, 0,-1,0, c, tx1,ty),
video::S3DVertex(vx2,vy,-0.5, 0,-1,0, c, tx2,ty),
video::S3DVertex(vx2,vy,+0.5, 0,-1,0, c, tx2,ty),
video::S3DVertex(vx1,vy,+0.5, 0,-1,0, c, tx1,ty),
};
u16 indices[6] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
x = xx - 1;
}
if (!scanline[x] && scanline[x + wstep])
{
u32 xx = x + 1;
while (!scanline[xx] && scanline[xx + wstep])
++xx;
f32 vx1 = (x - eps) / (f32) width - 0.5;
f32 vx2 = (xx + eps) / (f32) width - 0.5;
f32 vy = 0.5 - (y + eps) / (f32) height;
f32 tx1 = x / (f32) width;
f32 tx2 = xx / (f32) width;
f32 ty = (y + 0.5) / (f32) height;
video::S3DVertex vertices[8] =
{
video::S3DVertex(vx1,vy,-0.5, 0,1,0, c, tx1,ty),
video::S3DVertex(vx1,vy,+0.5, 0,1,0, c, tx1,ty),
video::S3DVertex(vx2,vy,+0.5, 0,1,0, c, tx2,ty),
video::S3DVertex(vx2,vy,-0.5, 0,1,0, c, tx2,ty),
};
u16 indices[6] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
x = xx - 1;
}
}
}
for (u32 x = 0; x <= width; ++x)
{
u8* scancol = solidity + x + wstep;
for (u32 y = 0; y <= height; ++y)
{
if (scancol[y * wstep] && !scancol[y * wstep + 1])
{
u32 yy = y + 1;
while (scancol[yy * wstep] && !scancol[yy * wstep + 1])
++yy;
f32 vx = (x - eps) / (f32) width - 0.5;
f32 vy1 = 0.5 - (y - eps) / (f32) height;
f32 vy2 = 0.5 - (yy + eps) / (f32) height;
f32 tx = (x - 0.5) / (f32) width;
f32 ty1 = y / (f32) height;
f32 ty2 = yy / (f32) height;
video::S3DVertex vertices[8] =
{
video::S3DVertex(vx,vy1,-0.5, 1,0,0, c, tx,ty1),
video::S3DVertex(vx,vy1,+0.5, 1,0,0, c, tx,ty1),
video::S3DVertex(vx,vy2,+0.5, 1,0,0, c, tx,ty2),
video::S3DVertex(vx,vy2,-0.5, 1,0,0, c, tx,ty2),
};
u16 indices[6] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
y = yy - 1;
}
if (!scancol[y * wstep] && scancol[y * wstep + 1])
{
u32 yy = y + 1;
while (!scancol[yy * wstep] && scancol[yy * wstep + 1])
++yy;
f32 vx = (x + eps) / (f32) width - 0.5;
f32 vy1 = 0.5 - (y - eps) / (f32) height;
f32 vy2 = 0.5 - (yy + eps) / (f32) height;
f32 tx = (x + 0.5) / (f32) width;
f32 ty1 = y / (f32) height;
f32 ty2 = yy / (f32) height;
video::S3DVertex vertices[8] =
{
video::S3DVertex(vx,vy1,-0.5, -1,0,0, c, tx,ty1),
video::S3DVertex(vx,vy2,-0.5, -1,0,0, c, tx,ty2),
video::S3DVertex(vx,vy2,+0.5, -1,0,0, c, tx,ty2),
video::S3DVertex(vx,vy1,+0.5, -1,0,0, c, tx,ty1),
};
u16 indices[6] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
y = yy - 1;
}
}
}
// Add to mesh
scene::SMesh* mesh = new scene::SMesh();
buf->recalculateBoundingBox();
mesh->addMeshBuffer(buf);
buf->drop();
mesh->recalculateBoundingBox();
scene::SAnimatedMesh* anim_mesh = new scene::SAnimatedMesh(mesh);
mesh->drop();
return anim_mesh;
}
scene::IAnimatedMesh* ExtrudedSpriteSceneNode::extrude(video::ITexture* texture)
{
scene::IAnimatedMesh* mesh = NULL;
core::dimension2d<u32> size = texture->getSize();
video::ECOLOR_FORMAT format = texture->getColorFormat();
if (format == video::ECF_A8R8G8B8)
{
// Texture is in the correct color format, we can pass it
// to extrudeARGB right away.
void* data = texture->lock(true);
if (data == NULL)
return NULL;
mesh = extrudeARGB(size.Width, size.Height, (u8*) data);
texture->unlock();
}
else
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
video::IImage* img1 = driver->createImageFromData(format, size, texture->lock(true));
if (img1 == NULL)
return NULL;
// img1 is in the texture's color format, convert to 8-bit ARGB
video::IImage* img2 = driver->createImage(video::ECF_A8R8G8B8, size);
if (img2 != NULL)
{
img1->copyTo(img2);
img1->drop();
mesh = extrudeARGB(size.Width, size.Height, (u8*) img2->lock());
img2->unlock();
img2->drop();
}
img1->drop();
}
return mesh;
}
scene::IMesh* ExtrudedSpriteSceneNode::createCubeMesh()
{
video::SColor c(255,255,255,255);
video::S3DVertex vertices[24] =
{
// Up
video::S3DVertex(-0.5,+0.5,-0.5, 0,1,0, c, 0,1),
video::S3DVertex(-0.5,+0.5,+0.5, 0,1,0, c, 0,0),
video::S3DVertex(+0.5,+0.5,+0.5, 0,1,0, c, 1,0),
video::S3DVertex(+0.5,+0.5,-0.5, 0,1,0, c, 1,1),
// Down
video::S3DVertex(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0),
video::S3DVertex(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0),
video::S3DVertex(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1),
video::S3DVertex(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1),
// Right
video::S3DVertex(+0.5,-0.5,-0.5, 1,0,0, c, 0,1),
video::S3DVertex(+0.5,+0.5,-0.5, 1,0,0, c, 0,0),
video::S3DVertex(+0.5,+0.5,+0.5, 1,0,0, c, 1,0),
video::S3DVertex(+0.5,-0.5,+0.5, 1,0,0, c, 1,1),
// Left
video::S3DVertex(-0.5,-0.5,-0.5, -1,0,0, c, 1,1),
video::S3DVertex(-0.5,-0.5,+0.5, -1,0,0, c, 0,1),
video::S3DVertex(-0.5,+0.5,+0.5, -1,0,0, c, 0,0),
video::S3DVertex(-0.5,+0.5,-0.5, -1,0,0, c, 1,0),
// Back
video::S3DVertex(-0.5,-0.5,+0.5, 0,0,1, c, 1,1),
video::S3DVertex(+0.5,-0.5,+0.5, 0,0,1, c, 0,1),
video::S3DVertex(+0.5,+0.5,+0.5, 0,0,1, c, 0,0),
video::S3DVertex(-0.5,+0.5,+0.5, 0,0,1, c, 1,0),
// Front
video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
};
u16 indices[6] = {0,1,2,2,3,0};
scene::SMesh* mesh = new scene::SMesh();
for (u32 i=0; i<6; ++i)
{
scene::IMeshBuffer* buf = new scene::SMeshBuffer();
buf->append(vertices + 4 * i, 4, indices, 6);
buf->recalculateBoundingBox();
mesh->addMeshBuffer(buf);
buf->drop();
}
mesh->recalculateBoundingBox();
return mesh;
}

230
src/camera.h Normal file

@ -0,0 +1,230 @@
/*
Minetest-c55
Copyright (C) 2010-2011 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
(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.
You should have received a copy of the GNU 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.
*/
#ifndef CAMERA_HEADER
#define CAMERA_HEADER
#include "common_irrlicht.h"
#include "inventory.h"
#include "tile.h"
#include "utility.h"
class LocalPlayer;
class MapDrawControl;
class ExtrudedSpriteSceneNode;
/*
Client camera class, manages the player and camera scene nodes, the viewing distance
and performs view bobbing etc. It also displays the wielded tool in front of the
first-person camera.
*/
class Camera
{
public:
Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control);
~Camera();
// Get player scene node.
// This node is positioned at the player's torso (without any view bobbing),
// as given by Player::m_position. Yaw is applied but not pitch.
inline scene::ISceneNode* getPlayerNode() const
{
return m_playernode;
}
// Get head scene node.
// It has the eye transformation and pitch applied,
// but no view bobbing.
inline scene::ISceneNode* getHeadNode() const
{
return m_headnode;
}
// Get camera scene node.
// It has the eye transformation, pitch and view bobbing applied.
inline scene::ICameraSceneNode* getCameraNode() const
{
return m_cameranode;
}
// Get the camera position (in absolute scene coordinates).
// This has view bobbing applied.
inline v3f getPosition() const
{
return m_camera_position;
}
// Get the camera direction (in absolute camera coordinates).
// This has view bobbing applied.
inline v3f getDirection() const
{
return m_camera_direction;
}
// Horizontal field of view
inline f32 getFovX() const
{
return m_fov_x;
}
// Vertical field of view
inline f32 getFovY() const
{
return m_fov_y;
}
// Get maximum of getFovX() and getFovY()
inline f32 getFovMax() const
{
return MYMAX(m_fov_x, m_fov_y);
}
// Checks if the constructor was able to create the scene nodes
bool successfullyCreated(std::wstring& error_message);
// Step the camera: updates the viewing range and view bobbing.
void step(f32 dtime);
// Update the camera from the local player's position.
// frametime is used to adjust the viewing range.
void update(LocalPlayer* player, f32 frametime, v2u32 screensize);
// Render distance feedback loop
void updateViewingRange(f32 frametime_in);
// Update settings from g_settings
void updateSettings();
// Replace the wielded item mesh
void wield(const InventoryItem* item);
// Start digging animation
// Pass 0 for left click, 1 for right click
void setDigging(s32 button);
// Draw the wielded tool.
// This has to happen *after* the main scene is drawn.
// Warning: This clears the Z buffer.
void drawWieldedTool();
private:
// Scene manager and nodes
scene::ISceneManager* m_smgr;
scene::ISceneNode* m_playernode;
scene::ISceneNode* m_headnode;
scene::ICameraSceneNode* m_cameranode;
scene::ISceneManager* m_wieldmgr;
ExtrudedSpriteSceneNode* m_wieldnode;
// draw control
MapDrawControl& m_draw_control;
// viewing_range_min_nodes setting
f32 m_viewing_range_min;
// viewing_range_max_nodes setting
f32 m_viewing_range_max;
// Absolute camera position
v3f m_camera_position;
// Absolute camera direction
v3f m_camera_direction;
// Field of view and aspect ratio stuff
f32 m_aspect;
f32 m_fov_x;
f32 m_fov_y;
// Stuff for viewing range calculations
f32 m_wanted_frametime;
f32 m_added_frametime;
s16 m_added_frames;
f32 m_range_old;
f32 m_frametime_old;
f32 m_frametime_counter;
f32 m_time_per_range;
// View bobbing animation frame (0 <= m_view_bobbing_anim < 1)
f32 m_view_bobbing_anim;
// If 0, view bobbing is off (e.g. player is standing).
// If 1, view bobbing is on (player is walking).
// If 2, view bobbing is getting switched off.
s32 m_view_bobbing_state;
// Speed of view bobbing animation
f32 m_view_bobbing_speed;
// Digging animation frame (0 <= m_digging_anim < 1)
f32 m_digging_anim;
// If -1, no digging animation
// If 0, left-click digging animation
// If 1, right-click digging animation
s32 m_digging_button;
};
/*
A scene node that displays a 2D mesh extruded into the third dimension,
to add an illusion of depth.
Since this class was created to display the wielded tool of the local
player, and only tools and items are rendered like this (but not solid
content like stone and mud, which are shown as cubes), the option to
draw a textured cube instead is provided.
*/
class ExtrudedSpriteSceneNode: public scene::ISceneNode
{
public:
ExtrudedSpriteSceneNode(
scene::ISceneNode* parent,
scene::ISceneManager* mgr,
s32 id = -1,
const v3f& position = v3f(0,0,0),
const v3f& rotation = v3f(0,0,0),
const v3f& scale = v3f(1,1,1));
~ExtrudedSpriteSceneNode();
void setSprite(video::ITexture* texture);
void setCube(const TileSpec tiles[6]);
f32 getSpriteThickness() const { return m_thickness; }
void setSpriteThickness(f32 thickness);
void updateLight(u8 light);
void removeSpriteFromCache(video::ITexture* texture);
virtual const core::aabbox3d<f32>& getBoundingBox() const;
virtual void OnRegisterSceneNode();
virtual void render();
private:
scene::IMeshSceneNode* m_meshnode;
f32 m_thickness;
scene::IMesh* m_cubemesh;
bool m_is_cube;
u8 m_light;
// internal extrusion helper methods
io::path getExtrudedName(video::ITexture* texture);
scene::IAnimatedMesh* extrudeARGB(u32 width, u32 height, u8* data);
scene::IAnimatedMesh* extrude(video::ITexture* texture);
scene::IMesh* createCubeMesh();
};
#endif

@ -189,8 +189,6 @@ Client::Client(
),
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
m_device(device),
camera_position(0,0,0),
camera_direction(0,0,1),
m_server_ser_ver(SER_FMT_VER_INVALID),
m_inventory_updated(false),
m_time_of_day(0),
@ -1981,11 +1979,14 @@ void Client::addNode(v3s16 p, MapNode n)
}
}
void Client::updateCamera(v3f pos, v3f dir)
void Client::updateCamera(v3f pos, v3f dir, f32 fov)
{
m_env.getClientMap().updateCamera(pos, dir);
camera_position = pos;
camera_direction = dir;
m_env.getClientMap().updateCamera(pos, dir, fov);
}
void Client::renderPostFx()
{
m_env.getClientMap().renderPostFx();
}
MapNode Client::getNode(v3s16 p)
@ -1999,14 +2000,9 @@ NodeMetadata* Client::getNodeMetadata(v3s16 p)
return m_env.getMap().getNodeMetadata(p);
}
v3f Client::getPlayerPosition(v3f *eye_position)
LocalPlayer* Client::getLocalPlayer()
{
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
LocalPlayer *player = m_env.getLocalPlayer();
assert(player != NULL);
if (eye_position)
*eye_position = player->getEyePosition();
return player->getPosition();
return m_env.getLocalPlayer();
}
void Client::setPlayerControl(PlayerControl &control)

@ -199,16 +199,16 @@ public:
// locks envlock
void addNode(v3s16 p, MapNode n);
void updateCamera(v3f pos, v3f dir);
void updateCamera(v3f pos, v3f dir, f32 fov);
void renderPostFx();
// Returns InvalidPositionException if not found
MapNode getNode(v3s16 p);
// Wrapper to Map
NodeMetadata* getNodeMetadata(v3s16 p);
// Get the player position, and optionally put the
// eye position in *eye_position
v3f getPlayerPosition(v3f *eye_position=NULL);
LocalPlayer* getLocalPlayer();
void setPlayerControl(PlayerControl &control);
@ -303,15 +303,6 @@ public:
return m_access_denied_reason;
}
/*
This should only be used for calling the special drawing stuff in
ClientEnvironment
*/
ClientEnvironment * getEnv()
{
return &m_env;
}
private:
// Virtual methods from con::PeerHandler
@ -342,9 +333,6 @@ private:
IrrlichtDevice *m_device;
v3f camera_position;
v3f camera_direction;
// Server serialization version
u8 m_server_ser_ver;

@ -44,9 +44,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PI 3.14159
// This is the same as in minecraft and everything else
#define FOV_ANGLE (PI/2.5)
// The absolute working limit is (2^15 - viewing_range).
// I really don't want to make every algorithm to check if it's
// going near the limit or not, so this is lower.

@ -224,22 +224,7 @@ void ItemCAO::updateLight(u8 light_at_pos)
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
scene::IMesh *mesh = m_node->getMesh();
if(mesh == NULL)
return;
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
v3s16 ItemCAO::getLightPosition()
@ -430,22 +415,7 @@ void RatCAO::updateLight(u8 light_at_pos)
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
scene::IMesh *mesh = m_node->getMesh();
if(mesh == NULL)
return;
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
v3s16 RatCAO::getLightPosition()
@ -601,22 +571,7 @@ void Oerkki1CAO::updateLight(u8 light_at_pos)
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
scene::IMesh *mesh = m_node->getMesh();
if(mesh == NULL)
return;
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
v3s16 Oerkki1CAO::getLightPosition()
@ -833,22 +788,7 @@ void FireflyCAO::updateLight(u8 light_at_pos)
u8 li = 255;
video::SColor color(255,li,li,li);
scene::IMesh *mesh = m_node->getMesh();
if(mesh == NULL)
return;
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
v3s16 FireflyCAO::getLightPosition()

@ -236,6 +236,8 @@ void content_mapnode_init()
if(new_style_leaves)
{
f->solidness = 0; // drawn separately, makes no faces
f->visual_solidness = 1;
f->setAllTextures("leaves.png");
f->setInventoryTextureCube("leaves.png", "leaves.png", "leaves.png");
}
else
@ -287,6 +289,8 @@ void content_mapnode_init()
f->is_ground_content = true;
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->solidness = 0; // drawn separately, makes no faces
f->visual_solidness = 1;
f->setAllTextures("glass.png");
f->setInventoryTextureCube("glass.png", "glass.png", "glass.png");
setWoodLikeDiggingProperties(f->digging_properties, 0.15);
@ -385,6 +389,7 @@ void content_mapnode_init()
f->liquid_alternative_source = CONTENT_WATERSOURCE;
f->liquid_viscosity = WATER_VISC;
f->vertex_alpha = WATER_ALPHA;
f->post_effect_color = video::SColor(64, 100, 100, 200);
if(f->special_material == NULL && g_texturesource)
{
// Flowing water material
@ -433,6 +438,7 @@ void content_mapnode_init()
f->liquid_alternative_source = CONTENT_WATERSOURCE;
f->liquid_viscosity = WATER_VISC;
f->vertex_alpha = WATER_ALPHA;
f->post_effect_color = video::SColor(64, 100, 100, 200);
if(f->special_material == NULL && g_texturesource)
{
// Flowing water material
@ -465,6 +471,7 @@ void content_mapnode_init()
f->liquid_alternative_source = CONTENT_LAVASOURCE;
f->liquid_viscosity = LAVA_VISC;
f->damage_per_second = 4*2;
f->post_effect_color = video::SColor(192, 255, 64, 0);
if(f->special_material == NULL && g_texturesource)
{
// Flowing lava material
@ -514,6 +521,7 @@ void content_mapnode_init()
f->liquid_alternative_source = CONTENT_LAVASOURCE;
f->liquid_viscosity = LAVA_VISC;
f->damage_per_second = 4*2;
f->post_effect_color = video::SColor(192, 255, 64, 0);
if(f->special_material == NULL && g_texturesource)
{
// Flowing lava material

@ -59,6 +59,8 @@ void set_default_settings()
g_settings.setDefault("random_input", "false");
g_settings.setDefault("client_unload_unused_data_timeout", "600");
g_settings.setDefault("enable_fog", "true");
g_settings.setDefault("fov", "72");
g_settings.setDefault("view_bobbing", "true");
g_settings.setDefault("new_style_water", "false");
g_settings.setDefault("new_style_leaves", "true");
g_settings.setDefault("smooth_lighting", "true");

@ -1687,7 +1687,9 @@ void ClientEnvironment::step(float dtime)
// Move
player->move(dtime, *m_map, 100*BS);
// Update lighting on remote players on client
}
// Update lighting on all players on client
u8 light = LIGHT_MAX;
try{
// Get node at head
@ -1697,7 +1699,6 @@ void ClientEnvironment::step(float dtime)
}
catch(InvalidPositionException &e) {}
player->updateLight(light);
}
/*
Add footsteps to grass
@ -1941,29 +1942,6 @@ ClientEnvEvent ClientEnvironment::getClientEvent()
return m_client_event_queue.pop_front();
}
void ClientEnvironment::drawPostFx(video::IVideoDriver* driver, v3f camera_pos)
{
/*LocalPlayer *player = getLocalPlayer();
assert(player);
v3f pos_f = player->getPosition() + v3f(0,BS*1.625,0);*/
v3f pos_f = camera_pos;
v3s16 p_nodes = floatToInt(pos_f, BS);
MapNode n = m_map->getNodeNoEx(p_nodes);
if(n.getContent() == CONTENT_WATER || n.getContent() == CONTENT_WATERSOURCE)
{
v2u32 ss = driver->getScreenSize();
core::rect<s32> rect(0,0, ss.X, ss.Y);
driver->draw2DRectangle(video::SColor(64, 100, 100, 200), rect);
}
else if(content_features(n).solidness == 2 &&
g_settings.getBool("free_move") == false)
{
v2u32 ss = driver->getScreenSize();
core::rect<s32> rect(0,0, ss.X, ss.Y);
driver->draw2DRectangle(video::SColor(255, 0, 0, 0), rect);
}
}
#endif // #ifndef SERVER

@ -407,9 +407,6 @@ public:
// Get event from queue. CEE_NONE is returned if queue is empty.
ClientEnvEvent getClientEvent();
// Post effects
void drawPostFx(video::IVideoDriver* driver, v3f camera_pos);
private:
ClientMap *m_map;
scene::ISceneManager *m_smgr;

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "materials.h"
#include "config.h"
#include "clouds.h"
#include "camera.h"
#include "farmesh.h"
#include "mapblock.h"
@ -49,8 +50,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define FIELD_OF_VIEW_TEST 0
MapDrawControl draw_control;
// Chat data
struct ChatLine
{
@ -143,144 +142,6 @@ struct TextDestSignNode : public TextDest
Client *m_client;
};
/*
Render distance feedback loop
*/
void updateViewingRange(f32 frametime_in, Client *client)
{
if(draw_control.range_all == true)
return;
static f32 added_frametime = 0;
static s16 added_frames = 0;
added_frametime += frametime_in;
added_frames += 1;
// Actually this counter kind of sucks because frametime is busytime
static f32 counter = 0;
counter -= frametime_in;
if(counter > 0)
return;
//counter = 0.1;
counter = 0.2;
/*dstream<<__FUNCTION_NAME
<<": Collected "<<added_frames<<" frames, total of "
<<added_frametime<<"s."<<std::endl;*/
/*dstream<<"draw_control.blocks_drawn="
<<draw_control.blocks_drawn
<<", draw_control.blocks_would_have_drawn="
<<draw_control.blocks_would_have_drawn
<<std::endl;*/
float range_min = g_settings.getS16("viewing_range_nodes_min");
float range_max = g_settings.getS16("viewing_range_nodes_max");
// Limit minimum to keep the feedback loop stable
if(range_min < 5)
range_min = 5;
draw_control.wanted_min_range = range_min;
//draw_control.wanted_max_blocks = (1.5*draw_control.blocks_drawn)+1;
draw_control.wanted_max_blocks = (1.5*draw_control.blocks_would_have_drawn)+1;
if(draw_control.wanted_max_blocks < 10)
draw_control.wanted_max_blocks = 10;
float block_draw_ratio = 1.0;
if(draw_control.blocks_would_have_drawn != 0)
{
block_draw_ratio = (float)draw_control.blocks_drawn
/ (float)draw_control.blocks_would_have_drawn;
}
// Calculate the average frametime in the case that all wanted
// blocks had been drawn
f32 frametime = added_frametime / added_frames / block_draw_ratio;
added_frametime = 0.0;
added_frames = 0;
float wanted_fps = g_settings.getFloat("wanted_fps");
float wanted_frametime = 1.0 / wanted_fps;
f32 wanted_frametime_change = wanted_frametime - frametime;
//dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
// If needed frametime change is small, just return
if(fabs(wanted_frametime_change) < wanted_frametime*0.4)
{
//dstream<<"ignoring small wanted_frametime_change"<<std::endl;
return;
}
float range = draw_control.wanted_range;
float new_range = range;
static s16 range_old = 0;
static f32 frametime_old = 0;
float d_range = range - range_old;
f32 d_frametime = frametime - frametime_old;
// A sane default of 30ms per 50 nodes of range
static f32 time_per_range = 30. / 50;
if(d_range != 0)
{
time_per_range = d_frametime / d_range;
}
// The minimum allowed calculated frametime-range derivative:
// Practically this sets the maximum speed of changing the range.
// The lower this value, the higher the maximum changing speed.
// A low value here results in wobbly range (0.001)
// A high value here results in slow changing range (0.0025)
// SUGG: This could be dynamically adjusted so that when
// the camera is turning, this is lower
//float min_time_per_range = 0.0015;
float min_time_per_range = 0.0010;
//float min_time_per_range = 0.05 / range;
if(time_per_range < min_time_per_range)
{
time_per_range = min_time_per_range;
//dstream<<"time_per_range="<<time_per_range<<" (min)"<<std::endl;
}
else
{
//dstream<<"time_per_range="<<time_per_range<<std::endl;
}
f32 wanted_range_change = wanted_frametime_change / time_per_range;
// Dampen the change a bit to kill oscillations
//wanted_range_change *= 0.9;
//wanted_range_change *= 0.75;
wanted_range_change *= 0.5;
//dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;
// If needed range change is very small, just return
if(fabs(wanted_range_change) < 0.001)
{
//dstream<<"ignoring small wanted_range_change"<<std::endl;
return;
}
new_range += wanted_range_change;
//float new_range_unclamped = new_range;
if(new_range < range_min)
new_range = range_min;
if(new_range > range_max)
new_range = range_max;
/*dstream<<"new_range="<<new_range_unclamped
<<", clamped to "<<new_range<<std::endl;*/
draw_control.wanted_range = new_range;
range_old = new_range;
frametime_old = frametime;
}
/*
Hotbar draw routine
*/
@ -847,6 +708,7 @@ void the_game(
draw_load_screen(L"Creating client...", driver, font);
std::cout<<DTIME<<"Creating client"<<std::endl;
MapDrawControl draw_control;
Client client(device, playername.c_str(), password, draw_control);
draw_load_screen(L"Resolving address...", driver, font);
@ -950,24 +812,9 @@ void the_game(
/*
Create the camera node
*/
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(
0, // Camera parent
v3f(BS*100, BS*2, BS*100), // Look from
v3f(BS*100+1, BS*2, BS*100), // Look to
-1 // Camera ID
);
if(camera == NULL)
{
error_message = L"Failed to create the camera node";
Camera camera(smgr, draw_control);
if (!camera.successfullyCreated(error_message))
return;
}
camera->setFOV(FOV_ANGLE);
// Just so big a value that everything rendered is visible
camera->setFarValue(100000*BS);
f32 camera_yaw = 0; // "right/left"
f32 camera_pitch = 0; // "up/down"
@ -1168,12 +1015,6 @@ void the_game(
// Necessary for device->getTimer()->getTime()
device->run();
/*
Viewing range
*/
updateViewingRange(busytime, &client);
/*
FPS limiter
*/
@ -1495,6 +1336,57 @@ void the_game(
debug_stacks_print();
}
/*
Mouse and camera control
NOTE: Do this before client.setPlayerControl() to not cause a camera lag of one frame
*/
if((device->isWindowActive() && noMenuActive()) || random_input)
{
if(!random_input)
{
// Mac OSX gets upset if this is set every frame
if(device->getCursorControl()->isVisible())
device->getCursorControl()->setVisible(false);
}
if(first_loop_after_window_activation){
//std::cout<<"window active, first loop"<<std::endl;
first_loop_after_window_activation = false;
}
else{
s32 dx = input->getMousePos().X - displaycenter.X;
s32 dy = input->getMousePos().Y - displaycenter.Y;
if(invert_mouse)
dy = -dy;
//std::cout<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
/*const float keyspeed = 500;
if(input->isKeyDown(irr::KEY_UP))
dy -= dtime * keyspeed;
if(input->isKeyDown(irr::KEY_DOWN))
dy += dtime * keyspeed;
if(input->isKeyDown(irr::KEY_LEFT))
dx -= dtime * keyspeed;
if(input->isKeyDown(irr::KEY_RIGHT))
dx += dtime * keyspeed;*/
camera_yaw -= dx*0.2;
camera_pitch += dy*0.2;
if(camera_pitch < -89.5) camera_pitch = -89.5;
if(camera_pitch > 89.5) camera_pitch = 89.5;
}
input->setMousePos(displaycenter.X, displaycenter.Y);
}
else{
// Mac OSX gets upset if this is set every frame
if(device->getCursorControl()->isVisible() == false)
device->getCursorControl()->setVisible(true);
//std::cout<<"window inactive"<<std::endl;
first_loop_after_window_activation = true;
}
/*
Player speed control
TODO: Cache the keycodes from getKeySetting
@ -1565,79 +1457,25 @@ void the_game(
}
}
// Get player position
v3f camera_position;
v3f player_position = client.getPlayerPosition(&camera_position);
//TimeTaker //timer2("//timer2");
/*
Mouse and camera control
*/
LocalPlayer* player = client.getLocalPlayer();
camera.update(player, busytime, screensize);
camera.step(dtime);
if((device->isWindowActive() && noMenuActive()) || random_input)
v3f player_position = player->getPosition();
v3f camera_position = camera.getPosition();
v3f camera_direction = camera.getDirection();
f32 camera_fov = camera.getFovMax();
if(FIELD_OF_VIEW_TEST)
{
if(!random_input)
client.updateCamera(v3f(0,0,0), v3f(0,0,1), camera_fov);
}
else
{
// Mac OSX gets upset if this is set every frame
if(device->getCursorControl()->isVisible())
device->getCursorControl()->setVisible(false);
}
if(first_loop_after_window_activation){
//std::cout<<"window active, first loop"<<std::endl;
first_loop_after_window_activation = false;
}
else{
s32 dx = input->getMousePos().X - displaycenter.X;
s32 dy = input->getMousePos().Y - displaycenter.Y;
if(invert_mouse)
dy = -dy;
//std::cout<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
/*const float keyspeed = 500;
if(input->isKeyDown(irr::KEY_UP))
dy -= dtime * keyspeed;
if(input->isKeyDown(irr::KEY_DOWN))
dy += dtime * keyspeed;
if(input->isKeyDown(irr::KEY_LEFT))
dx -= dtime * keyspeed;
if(input->isKeyDown(irr::KEY_RIGHT))
dx += dtime * keyspeed;*/
camera_yaw -= dx*0.2;
camera_pitch += dy*0.2;
if(camera_pitch < -89.5) camera_pitch = -89.5;
if(camera_pitch > 89.5) camera_pitch = 89.5;
}
input->setMousePos(displaycenter.X, displaycenter.Y);
}
else{
// Mac OSX gets upset if this is set every frame
if(device->getCursorControl()->isVisible() == false)
device->getCursorControl()->setVisible(true);
//std::cout<<"window inactive"<<std::endl;
first_loop_after_window_activation = true;
}
camera_yaw = wrapDegrees(camera_yaw);
camera_pitch = wrapDegrees(camera_pitch);
v3f camera_direction = v3f(0,0,1);
camera_direction.rotateYZBy(camera_pitch);
camera_direction.rotateXZBy(camera_yaw);
camera->setPosition(camera_position);
// *100.0 helps in large map coordinates
camera->setTarget(camera_position + camera_direction * 100.0);
if(FIELD_OF_VIEW_TEST){
client.updateCamera(v3f(0,0,0), v3f(0,0,1));
}
else{
//TimeTaker timer("client.updateCamera");
client.updateCamera(camera_position, camera_direction);
client.updateCamera(camera_position,
camera_direction, camera_fov);
}
//timer2.stop();
@ -1917,9 +1755,12 @@ void the_game(
}
dig_time += dtime;
camera.setDigging(0); // left click animation
}
}
if(input->getRightClicked())
{
std::cout<<DTIME<<"Ground right-clicked"<<std::endl;
@ -1978,16 +1819,20 @@ void the_game(
else
{
client.groundAction(1, nodepos, neighbourpos, g_selected_item);
camera.setDigging(1); // right click animation
}
}
nodepos_old = nodepos;
}
else{
}
} // selected_object == NULL
if(input->getLeftClicked())
{
camera.setDigging(0); // left click animation
}
input->resetLeftClicked();
input->resetRightClicked();
@ -2010,8 +1855,6 @@ void the_game(
Calculate stuff for drawing
*/
camera->setAspectRatio((f32)screensize.X / (f32)screensize.Y);
u32 daynight_ratio = client.getDayNightRatio();
u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000);
video::SColor bgcolor = video::SColor(
@ -2032,7 +1875,7 @@ void the_game(
update_skybox(driver, smgr, skybox, brightness);
/*
Update coulds
Update clouds
*/
if(clouds)
{
@ -2103,7 +1946,6 @@ void the_game(
);
}
/*
Update gui stuff (0ms)
*/
@ -2249,6 +2091,13 @@ void the_game(
old_selected_item = g_selected_item;
//std::cout<<"Updating local inventory"<<std::endl;
client.getLocalInventory(local_inventory);
// Update wielded tool
InventoryList *mlist = local_inventory.getList("main");
InventoryItem *item = NULL;
if(mlist != NULL)
item = mlist->getItem(g_selected_item);
camera.wield(item);
}
/*
@ -2313,6 +2162,21 @@ void the_game(
driver->draw3DBox(*i, video::SColor(255,0,0,0));
}
/*
Wielded tool
*/
{
// Warning: This clears the Z buffer.
camera.drawWieldedTool();
}
/*
Post effects
*/
{
client.renderPostFx();
}
/*
Frametime log
*/
@ -2352,13 +2216,6 @@ void the_game(
// 0-1ms
guienv->drawAll();
/*
Environment post fx
*/
{
client.getEnv()->drawPostFx(driver, camera_position);
}
/*
Draw hotbar
*/

@ -158,7 +158,7 @@ InventoryItem *MaterialItem::createCookResult() const
*/
#ifndef SERVER
video::ITexture * CraftItem::getImage()
video::ITexture * CraftItem::getImage() const
{
if(g_texturesource == NULL)
return NULL;
@ -224,7 +224,7 @@ bool CraftItem::use(ServerEnvironment *env, Player *player)
TODO: Remove
*/
#ifndef SERVER
video::ITexture * MapBlockObjectItem::getImage()
video::ITexture * MapBlockObjectItem::getImage() const
{
if(m_inventorystring.substr(0,3) == "Rat")
return g_texturesource->getTextureRaw("rat.png");

@ -53,8 +53,12 @@ public:
// Shall make an exact clone of the item
virtual InventoryItem* clone() = 0;
#ifndef SERVER
// Shall return an image to show in the GUI (or NULL)
virtual video::ITexture * getImage() { return NULL; }
// Return the name of the image for this item
virtual std::string getBasename() const { return ""; }
// Shall return an image of the item (or NULL)
virtual video::ITexture * getImage() const { return NULL; }
// Shall return an image of the item without embellishments (or NULL)
virtual video::ITexture * getImageRaw() const { return getImage(); }
#endif
// Shall return a text to show in the GUI
virtual std::string getText() { return ""; }
@ -149,10 +153,9 @@ public:
return new MaterialItem(m_content, m_count);
}
#ifndef SERVER
video::ITexture * getImage()
video::ITexture * getImage() const
{
return content_features(m_content).inventory_texture;
return NULL;
}
#endif
std::string getText()
@ -225,7 +228,7 @@ public:
}
#ifndef SERVER
video::ITexture * getImage();
video::ITexture * getImage() const;
#endif
std::string getText();
@ -276,7 +279,7 @@ public:
return new CraftItem(m_subname, m_count);
}
#ifndef SERVER
video::ITexture * getImage();
video::ITexture * getImage() const;
#endif
std::string getText()
{
@ -353,40 +356,43 @@ public:
return new ToolItem(m_toolname, m_wear);
}
#ifndef SERVER
video::ITexture * getImage()
std::string getBasename() const {
if(m_toolname == "WPick")
return "tool_woodpick.png";
else if(m_toolname == "STPick")
return "tool_stonepick.png";
else if(m_toolname == "SteelPick")
return "tool_steelpick.png";
else if(m_toolname == "MesePick")
return "tool_mesepick.png";
else if(m_toolname == "WShovel")
return "tool_woodshovel.png";
else if(m_toolname == "STShovel")
return "tool_stoneshovel.png";
else if(m_toolname == "SteelShovel")
return "tool_steelshovel.png";
else if(m_toolname == "WAxe")
return "tool_woodaxe.png";
else if(m_toolname == "STAxe")
return "tool_stoneaxe.png";
else if(m_toolname == "SteelAxe")
return "tool_steelaxe.png";
else if(m_toolname == "WSword")
return "tool_woodsword.png";
else if(m_toolname == "STSword")
return "tool_stonesword.png";
else if(m_toolname == "SteelSword")
return "tool_steelsword.png";
else
return "cloud.png";
}
video::ITexture * getImage() const
{
if(g_texturesource == NULL)
return NULL;
std::string basename;
if(m_toolname == "WPick")
basename = "tool_woodpick.png";
else if(m_toolname == "STPick")
basename = "tool_stonepick.png";
else if(m_toolname == "SteelPick")
basename = "tool_steelpick.png";
else if(m_toolname == "MesePick")
basename = "tool_mesepick.png";
else if(m_toolname == "WShovel")
basename = "tool_woodshovel.png";
else if(m_toolname == "STShovel")
basename = "tool_stoneshovel.png";
else if(m_toolname == "SteelShovel")
basename = "tool_steelshovel.png";
else if(m_toolname == "WAxe")
basename = "tool_woodaxe.png";
else if(m_toolname == "STAxe")
basename = "tool_stoneaxe.png";
else if(m_toolname == "SteelAxe")
basename = "tool_steelaxe.png";
else if(m_toolname == "WSword")
basename = "tool_woodsword.png";
else if(m_toolname == "STSword")
basename = "tool_stonesword.png";
else if(m_toolname == "SteelSword")
basename = "tool_steelsword.png";
else
basename = "cloud.png";
std::string basename = getBasename();
/*
Calculate a progress value with sane amount of
@ -401,6 +407,14 @@ public:
return g_texturesource->getTextureRaw(os.str());
}
video::ITexture * getImageRaw() const
{
if(g_texturesource == NULL)
return NULL;
return g_texturesource->getTextureRaw(getBasename());
}
#endif
std::string getText()
{

@ -3606,7 +3606,8 @@ ClientMap::ClientMap(
m_client(client),
m_control(control),
m_camera_position(0,0,0),
m_camera_direction(0,0,1)
m_camera_direction(0,0,1),
m_camera_fov(PI)
{
m_camera_mutex.Init();
assert(m_camera_mutex.IsInitialized());
@ -3715,6 +3716,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
m_camera_mutex.Lock();
v3f camera_position = m_camera_position;
v3f camera_direction = m_camera_direction;
f32 camera_fov = m_camera_fov;
m_camera_mutex.Unlock();
/*
@ -3807,7 +3809,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
float d = 0.0;
if(isBlockInSight(block->getPos(), camera_position,
camera_direction, range, &d) == false)
camera_direction, camera_fov,
range, &d) == false)
{
continue;
}
@ -3927,6 +3930,35 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
<<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
}
void ClientMap::renderPostFx()
{
// Sadly ISceneManager has no "post effects" render pass, in that case we
// could just register for that and handle it in renderMap().
m_camera_mutex.Lock();
v3f camera_position = m_camera_position;
m_camera_mutex.Unlock();
MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
// - If the player is in a solid node, make everything black.
// - If the player is in liquid, draw a semi-transparent overlay.
ContentFeatures& features = content_features(n);
video::SColor post_effect_color = features.post_effect_color;
if(features.solidness == 2 && g_settings.getBool("free_move") == false)
{
post_effect_color = video::SColor(255, 0, 0, 0);
}
if (post_effect_color.getAlpha() != 0)
{
// Draw a full-screen rectangle
video::IVideoDriver* driver = SceneManager->getVideoDriver();
v2u32 ss = driver->getScreenSize();
core::rect<s32> rect(0,0, ss.X, ss.Y);
driver->draw2DRectangle(post_effect_color, rect);
}
}
bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
core::map<v3s16, MapBlock*> *affected_blocks)
{

@ -518,11 +518,12 @@ public:
ISceneNode::drop();
}
void updateCamera(v3f pos, v3f dir)
void updateCamera(v3f pos, v3f dir, f32 fov)
{
JMutexAutoLock lock(m_camera_mutex);
m_camera_position = pos;
m_camera_direction = dir;
m_camera_fov = fov;
}
/*
@ -552,6 +553,8 @@ public:
void renderMap(video::IVideoDriver* driver, s32 pass);
void renderPostFx();
/*
Methods for setting temporary modifications to nodes for
drawing.
@ -601,6 +604,7 @@ private:
v3f m_camera_position;
v3f m_camera_direction;
f32 m_camera_fov;
JMutex m_camera_mutex;
core::map<v2s16, bool> m_last_drawn_sectors;

@ -484,20 +484,7 @@ public:
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
scene::IMesh *mesh = m_node->getMesh();
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
#endif
@ -676,20 +663,7 @@ public:
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
scene::IMesh *mesh = m_node->getMesh();
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
#endif
@ -836,20 +810,7 @@ public:
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
scene::IMesh *mesh = m_node->getMesh();
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
#endif
@ -982,20 +943,7 @@ public:
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
scene::IMesh *mesh = m_node->getMesh();
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
#endif

@ -160,6 +160,8 @@ struct ContentFeatures
u8 liquid_viscosity;
// Used currently for flowing liquids
u8 vertex_alpha;
// Post effect color, drawn when the camera is inside the node.
video::SColor post_effect_color;
// Special irrlicht material, used sometimes
video::SMaterial *special_material;
AtlasPointer *special_atlas;
@ -197,6 +199,7 @@ struct ContentFeatures
liquid_alternative_source = CONTENT_IGNORE;
liquid_viscosity = 0;
vertex_alpha = 255;
post_effect_color = video::SColor(0, 0, 0, 0);
special_material = NULL;
special_atlas = NULL;
light_source = 0;

@ -67,12 +67,17 @@ public:
return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
}
v3f getEyePosition()
v3f getEyeOffset()
{
// This is at the height of the eyes of the current figure
// return m_position + v3f(0, BS+BS/2, 0);
// return v3f(0, BS+BS/2, 0);
// This is more like in minecraft
return m_position + v3f(0,BS+(5*BS)/8,0);
return v3f(0,BS+(5*BS)/8,0);
}
v3f getEyePosition()
{
return m_position + getEyeOffset();
}
virtual void setPosition(const v3f &position)
@ -121,7 +126,10 @@ public:
virtual bool isLocal() const = 0;
virtual void updateLight(u8 light_at_pos) {};
virtual void updateLight(u8 light_at_pos)
{
light = light_at_pos;
}
// NOTE: Use peer_id == 0 for disconnected
/*virtual bool isClientConnected() { return false; }
@ -144,6 +152,8 @@ public:
bool swimming_up;
bool is_frozen;
u8 light;
Inventory inventory;
// Actual inventory is backed up here when creative mode is used
Inventory *inventory_backup;
@ -261,25 +271,14 @@ public:
virtual void updateLight(u8 light_at_pos)
{
Player::updateLight(light_at_pos);
if(m_node == NULL)
return;
u8 li = decode_light(light_at_pos);
video::SColor color(255,li,li,li);
scene::IMesh *mesh = m_node->getMesh();
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
setMeshVerticesColor(m_node->getMesh(), color);
}
void move(f32 dtime, Map &map, f32 pos_max_d);

@ -582,9 +582,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
/*
Don't generate or send if not in sight
FIXME This only works if the client uses a small enough
FOV setting. The default of 72 degrees is fine.
*/
if(isBlockInSight(p, camera_pos, camera_dir, 10000*BS) == false)
float camera_fov = (72.0*PI/180) * 4./3.;
if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
{
continue;
}

@ -304,7 +304,7 @@ struct TileSpec
}
// Sets everything else except the texture in the material
void applyMaterialOptions(video::SMaterial &material)
void applyMaterialOptions(video::SMaterial &material) const
{
if(alpha != 255 && material_type != MATERIAL_ALPHA_VERTEX)
dstream<<"WARNING: TileSpec: alpha != 255 "

@ -156,14 +156,33 @@ void mysrand(unsigned seed)
next = seed;
}
// Sets the color of all vertices in the mesh
void setMeshVerticesColor(scene::IMesh* mesh, video::SColor& color)
{
if(mesh == NULL)
return;
u16 mc = mesh->getMeshBufferCount();
for(u16 j=0; j<mc; j++)
{
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
u16 vc = buf->getVertexCount();
for(u16 i=0; i<vc; i++)
{
vertices[i].Color = color;
}
}
}
/*
blockpos: position of block in block coordinates
camera_pos: position of camera in nodes
camera_dir: an unit vector pointing to camera direction
range: viewing range
*/
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
f32 *distance_ptr)
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
f32 camera_fov, f32 range, f32 *distance_ptr)
{
v3s16 blockpos_nodes = blockpos_b * MAP_BLOCKSIZE;
@ -211,8 +230,7 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
cosangle += block_max_radius / dforward;
// If block is not in the field of view, skip it
//if(cosangle < cos(FOV_ANGLE/2))
if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
if(cosangle < cos(camera_fov / 2))
return false;
}

@ -553,6 +553,9 @@ private:
u32 *m_result;
};
// Sets the color of all vertices in the mesh
void setMeshVerticesColor(scene::IMesh* mesh, video::SColor& color);
// Calculates the borders of a "d-radius" cube
inline void getFacePositions(core::list<v3s16> &list, u16 d)
{
@ -1765,8 +1768,8 @@ inline int myrand_range(int min, int max)
Miscellaneous functions
*/
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
f32 *distance_ptr=NULL);
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
f32 camera_fov, f32 range, f32 *distance_ptr=NULL);
/*
Queue with unique values with fast checking of value existence