* the camera is now located behind the character's back and follows his movement; zoom in/out works too. original patch by sbp, thx!

** note: press POS1 key to toggle movement/freefly mode
* fixed character movement without initial turn (before it went into a random direction if not turned - now its fine)
* fixed: really (un-)load maps when moving a longer distance
* improved graphical debugging: show all SceneNode bounding boxes & bones (if there are any) - press backspace to toggle debugging
* ISceneNodes can now be accessed via their owner's guids [use DrawObjMgr::Get(guid) and DrawObject::GetSceneNode()]
* added one more ByteBuffer output variant (combined hex/text), thx nitrogrlie!
This commit is contained in:
false_genesis 2008-08-11 23:52:42 +00:00
parent b56bc70f9a
commit 3b47963c5d
8 changed files with 213 additions and 21 deletions

View File

@ -96,3 +96,12 @@ void DrawObjMgr::Update(void)
//mut.release();
}
DrawObject *DrawObjMgr::Get(uint64 guid)
{
DrawObjStorage::iterator it = _storage.find(guid);
if(it != _storage.end())
return it->second;
return NULL;
}

View File

@ -18,6 +18,7 @@ public:
void Update(void); // Threadsafe! delete code must be called from here!
uint32 StorageSize(void) { return _storage.size(); }
void UnlinkAll(void);
DrawObject *Get(uint64);
private:
DrawObjStorage _storage;

View File

@ -105,8 +105,8 @@ void DrawObject::_Init(void)
//cube->getMaterial(0).DiffuseColor.setAlpha(opacity);
cube->setName("OBJECT");
//cube->getMaterial(0).setFlag(video::EMF_LIGHTING, true);
//cube->getMaterial(0).setFlag(video::EMF_FOG_ENABLE, true);
cube->getMaterial(0).setFlag(video::EMF_LIGHTING, true);
cube->getMaterial(0).setFlag(video::EMF_FOG_ENABLE, true);
text=_smgr->addTextSceneNode(_guienv->getBuiltInFont(), L"TestText" , irr::video::SColor(255,255,255,255),cube, irr::core::vector3df(0,5,0));
if(_obj->IsPlayer())

View File

@ -14,6 +14,7 @@ public:
~DrawObject();
void Draw(void); // call only in threadsafe environment!! (ensure the obj ptr is still valid!)
void Unlink(void);
inline irr::scene::ISceneNode *GetSceneNode(void) { return cube; }
// additionally, we dont use a GetObject() func - that would fuck things up if the object was already deleted.
private:

View File

@ -98,7 +98,9 @@ public:
void UpdateTerrain(void);
void InitTerrain(void);
void RelocateCamera(void);
void RelocateCameraBehindChar(void);
void UpdateDoodads(void);
scene::ISceneNode *GetMyCharacterSceneNode(void);
video::SColor GetBackgroundColor(void);
WorldPosition GetWorldPosition(void);
@ -124,6 +126,8 @@ private:
bool _freeCameraMove;
void _CalcXYMoveVect(float o);
core::vector2df xyCharMovement; // stores sin() and cos() values for current MyCharacter orientation, so that they need to be calculated only if the character turns around
bool mouse_pressed_left;
bool mouse_pressed_right;
};

View File

@ -13,6 +13,10 @@
#include "World.h"
#include "CCursorController.h"
#include "MovementMgr.h"
#include "DrawObject.h"
// TODO: replace this by conf value
#define MAX_CAM_DISTANCE 70
SceneWorld::SceneWorld(PseuGUI *g) : Scene(g)
{
@ -40,6 +44,7 @@ SceneWorld::SceneWorld(PseuGUI *g) : Scene(g)
eventrecv = new MyEventReceiver();
device->setEventReceiver(eventrecv);
eventrecv->mouse.wheel = MAX_CAM_DISTANCE;
camera = new MCameraFPS(smgr);
camera->setNearValue(0.1f);
@ -90,7 +95,7 @@ SceneWorld::SceneWorld(PseuGUI *g) : Scene(g)
InitTerrain();
UpdateTerrain();
RelocateCamera();
RelocateCameraBehindChar();
DEBUG(logdebug("SceneWorld: Init done!"));
}
@ -101,8 +106,8 @@ void SceneWorld::OnUpdate(s32 timediff)
UpdateTerrain();
bool mouse_pressed_left = eventrecv->mouse.left_pressed();
bool mouse_pressed_right = eventrecv->mouse.right_pressed();
mouse_pressed_left = eventrecv->mouse.left_pressed();
mouse_pressed_right = eventrecv->mouse.right_pressed();
float timediff_f = timediff / 1000.0f;
if( (mouse_pressed_right || mouse_pressed_left) && cursor->isVisible())
@ -124,8 +129,6 @@ void SceneWorld::OnUpdate(s32 timediff)
selectedNode = focusedNode;
}*/ // i'll continue working on this - [FG]
if(eventrecv->key.pressed_once(KEY_KEY_L))
((ICameraSceneNode*)camera->getNode())->setTarget(vector3df(0,0,0));
// maybe it is better to replace the sin() and cos() with some irr::core::matrix4 calcualtions... not sure what is more efficient
@ -139,6 +142,7 @@ void SceneWorld::OnUpdate(s32 timediff)
movemgr->SetMoveMode(MOVEMODE_MANUAL);
movemgr->MoveStartForward();
WorldPosition wp = mychar->GetPosition();
_CalcXYMoveVect(wp.o);
wp.x += (xyCharMovement.X * speedfactor);
wp.y += (xyCharMovement.Y * speedfactor);
wp.z = terrain->getHeight(WPToIrr(wp));
@ -156,6 +160,7 @@ void SceneWorld::OnUpdate(s32 timediff)
movemgr->SetMoveMode(MOVEMODE_MANUAL);
movemgr->MoveStartBackward();
WorldPosition wp = mychar->GetPosition();
_CalcXYMoveVect(wp.o);
wp.x -= (xyCharMovement.X * speedfactor);
wp.y -= (xyCharMovement.Y * speedfactor);
wp.z = terrain->getHeight(WPToIrr(wp));
@ -232,6 +237,7 @@ void SceneWorld::OnUpdate(s32 timediff)
movemgr->SetMoveMode(MOVEMODE_MANUAL);
movemgr->MoveStartStrafeRight();
WorldPosition wp = mychar->GetPosition();
_CalcXYMoveVect(wp.o);
wp.x -= (xyCharMovement.X * speedfactor);
wp.y -= (xyCharMovement.Y * speedfactor);
wp.z = terrain->getHeight(WPToIrr(wp));
@ -249,6 +255,7 @@ void SceneWorld::OnUpdate(s32 timediff)
movemgr->SetMoveMode(MOVEMODE_MANUAL);
movemgr->MoveStartStrafeLeft();
WorldPosition wp = mychar->GetPosition();
_CalcXYMoveVect(wp.o);
wp.x -= (xyCharMovement.X * speedfactor);
wp.y -= (xyCharMovement.Y * speedfactor);
wp.z = terrain->getHeight(WPToIrr(wp));
@ -294,19 +301,25 @@ void SceneWorld::OnUpdate(s32 timediff)
if(eventrecv->key.pressed_once(KEY_HOME))
{
_freeCameraMove = !_freeCameraMove;
// TODO: uncomment this as soon as the camera isn't adjusted anymore every single frame
//if(!_freeCameraMove)
// RelocateCameraBehindChar();
}
if(eventrecv->key.pressed_once(KEY_BACK))
{
debugmode = !debugmode;
if(debugmode)
// -- rendering with all debug flags uses WAY too much CPU to leave it turned on
E_DEBUG_SCENE_TYPE dflags = E_DEBUG_SCENE_TYPE(debugmode ? (EDS_BBOX | EDS_BBOX_BUFFERS | EDS_SKELETON) : EDS_OFF);
const core::list<scene::ISceneNode*>& nodelist = smgr->getRootSceneNode()->getChildren();
for(core::list<scene::ISceneNode*>::ConstIterator it = nodelist.begin(); it != nodelist.end(); it++)
{
terrain->setDebugDataVisible(EDS_FULL);
}
else
{
terrain->setDebugDataVisible(EDS_OFF);
(*it)->setDebugDataVisible(dflags);
}
// only terrain is especially useful with all debug flags enabled
terrain->setDebugDataVisible(debugmode ? EDS_FULL : EDS_OFF);
}
if(eventrecv->key.pressed_once(KEY_INSERT))
@ -334,6 +347,12 @@ void SceneWorld::OnUpdate(s32 timediff)
if(camera->getPitch() < 270 && camera->getPitch() > 90)
camera->turnUp(90);
// camera distance control
if (eventrecv->mouse.wheel < 0)
eventrecv->mouse.wheel = 0;
if(eventrecv->mouse.wheel > MAX_CAM_DISTANCE)
eventrecv->mouse.wheel = MAX_CAM_DISTANCE;
if(mouse_pressed_left || mouse_pressed_right)
{
if(mouse_pos != cursor->getMousePos())
@ -347,18 +366,29 @@ void SceneWorld::OnUpdate(s32 timediff)
camera->turnUp(upval);
}
device->getCursorControl()->setPosition(mouse_pos);
// TODO: implement charater turning on right-click-mouse-move.
// the code below doesnt work at all actually, no idea why. seems like camera interferes with mychar pos or so..
if(mouse_pressed_right)
{
mychar->GetPositionPtr()->o = IRR_TO_O(DEG_TO_RAD(camera->getHeading()));
}
}
}
else
{
//device->getCursorControl()->setPosition(device->getCursorControl()->getPosition());
mouse_pos = device->getCursorControl()->getPosition();
}
// camera height control
if (eventrecv->mouse.wheel < 2)
eventrecv->mouse.wheel = 2;
camera->setHeight( eventrecv->mouse.wheel + terrain->getHeight(camera->getPosition()) );
// TODO: check if the cam really has to be relocated; might save some CPU but not sure...
if(_freeCameraMove)
{
camera->setHeight( terrain->getHeight(camera->getPosition()) + 4 );
}
else
{
RelocateCameraBehindChar();
}
core::stringw str = L"";
@ -384,6 +414,8 @@ void SceneWorld::OnUpdate(s32 timediff)
str += L" (";
str += (u32)(((f32)terrain->getSectorsRendered()/(f32)terrain->getSectorCount())*100.0f);
str += L"%)";
str += L" mwheel=";
str += eventrecv->mouse.wheel;
str += L"\n";
@ -638,7 +670,7 @@ void SceneWorld::UpdateTerrain(void)
// TODO: check if camera should really be relocated -> in case we got teleported
// do NOT relocate camera if we moved around and triggered the map loading code by ourself!
RelocateCamera();
RelocateCameraBehindChar();
}
// drop unneeded doodads from the map
@ -665,9 +697,9 @@ void SceneWorld::RelocateCamera(void)
MyCharacter *my = wsession->GetMyChar();
if(my)
{
logdebug("SceneWorld: Relocating camera to MyCharacter");
//logdebug("SceneWorld: Relocating camera to MyCharacter");
camera->setPosition(vector3df(-my->GetX(),my->GetZ(),-my->GetY()));
camera->turnLeft(camera->getHeading() - O_TO_IRR(my->GetO()));
camera->turnLeft(camera->getHeading() - RAD_TO_DEG(PI*3/2 - my->GetO()));
}
else
{
@ -675,6 +707,56 @@ void SceneWorld::RelocateCamera(void)
}
}
// TODO: call this func only when really needed, and not in every loop?
void SceneWorld::RelocateCameraBehindChar(void)
{
if(mychar)
{
float distance = (MAX_CAM_DISTANCE / 5.0f) - (eventrecv->mouse.wheel / 5.0f);
//DEBUG(logdebug("SceneWorld: Relocating camera behind MyCharacter, dist %.2f",distance));
// TODO: partial transparency for near character zoom (TEST) [fg]
// didnt work at all, so if somebody knows how to set a model transparent please fix this!
/*
if(distance <= 4)
{
scene::ISceneNode *charnode = GetMyCharacterSceneNode(); // NOTE: this call is absolutely not optimized!
if(charnode)
{
charnode->getMaterial(0).MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
charnode->getMaterial(0).AmbientColor.setAlpha(distance * 50);
charnode->getMaterial(0).DiffuseColor.setAlpha(distance * 50);
}
}
*/
// WORKAROUND: if camera is too near, just make our player invisible
scene::ISceneNode *charnode = GetMyCharacterSceneNode(); // NOTE: this call is absolutely not optimized!
if(charnode)
{
if(distance <= 0.25f)
charnode->setVisible(false);
else
charnode->setVisible(true);
}
if(mouse_pressed_left)
{
camera->setPosition(vector3df(-mychar->GetX(), mychar->GetZ() + distance + 1.5f, -mychar->GetY()));
camera->moveBack(distance);
}
else
{
camera->setPosition(vector3df(-mychar->GetX(), mychar->GetZ() + distance + 1.5f, -mychar->GetY()));
camera->turnLeft(camera->getHeading() - RAD_TO_DEG(PI*3/2 - mychar->GetO()));
camera->moveBack(distance);
}
}
else
{
logerror("SceneWorld: Relocating camera behind MyCharacter - not found!");
}
}
WorldPosition SceneWorld::GetWorldPosition(void)
{
// TODO: later do not use CAMERA, but CHARACTER position, as soon as camera is changed from 1st to 3rd person view
@ -693,4 +775,10 @@ void SceneWorld::_CalcXYMoveVect(float o)
xyCharMovement.Y = sin(o);
}
scene::ISceneNode *SceneWorld::GetMyCharacterSceneNode(void)
{
DrawObject *d = gui->domgr.Get(mychar->GetGUID());
return d ? d->GetSceneNode() : NULL;
}

View File

@ -149,6 +149,13 @@ void MovementMgr::Update(bool sendDirect)
if( !sendDirect && (_moveFlags & MOVEMENTFLAG_ANY_MOVE_NOT_TURNING) && _optime + MOVE_HEARTBEAT_DELAY < getMSTime())
{
_BuildPacket(MSG_MOVE_HEARTBEAT);
// also need to tell the world map mgr that we moved; maybe maps need to be loaded
// the main thread will take care of really loading the maps; here we just tell our updated position
if(World *world = _instance->GetWSession()->GetWorld())
{
world->UpdatePos(pos.x, pos.y, world->GetMapId());
}
}
// TODO: apply gravity, handle falling, swimming, etc.
}

View File

@ -326,6 +326,87 @@ class ByteBuffer
printf("\n");
}
void print(void)
{
uint32 line = 1;
uint32 countpos = 0;
printf("STORAGE_SIZE: %u\n", size() );
printf("|------------------------------------------------|----------------|\r\n");
printf("|00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F |0123456789ABCDEF|\r\n");
printf("|------------------------------------------------|----------------|\r\n");
if (size() > 0)
{
printf("|");
for (uint32 count = 0; count < size(); count++)
{
if (countpos == 16)
{
countpos = 0;
printf("|");
for (uint32 a = count-16; a < count; a++)
{
if ((read<uint8>(a) < 32) || (read<uint8>(a) > 126))
printf(".");
else
printf("%c", read<uint8>(a));
}
printf("|\r\n");
line++;
printf("|");
}
printf("%02x ", read<uint8>(count));
// Fix to parse packets with length < OR = to 16 bytes.
if (count+1 == size() && size() <= 16)
{
for (uint32 b = countpos+1; b < 16; b++)
printf(" ");
printf("|");
for (uint32 a = 0; a < size(); a++)
{
if ((read<uint8>(a) < 32) || (read<uint8>(a) > 126))
printf(".");
else
printf("%c", read<uint8>(a));
}
for (uint32 c = count; c < 15; c++)
printf(" ");
printf("|\r\n");
}
// Fix to parse the last line of the packets when the length is > 16 and its in the last line
if (count+1 == size() && size() > 16)
{
for (uint32 b = countpos+1; b < 16; b++)
printf(" ");
printf("|");
uint16 print = 0;
for (uint32 a = line*16 - 16; a < size(); a++)
{
if ((read<uint8>(a) < 32) || (read<uint8>(a) > 126))
printf(".");
else
printf("%c", read<uint8>(a));
print++;
}
for (uint32 c = print; c < 16; c++)
printf(" ");
printf("|\r\n");
}
countpos++;
}
}
printf("-------------------------------------------------------------------\r\n\r\n");
}
protected:
@ -405,4 +486,5 @@ template <typename K, typename V> ByteBuffer &operator>>(ByteBuffer &b, std::map
}
return b;
}
#endif