From 3b47963c5dc69b3825f6bbfe27f9b607ee2bfafa Mon Sep 17 00:00:00 2001 From: false_genesis Date: Mon, 11 Aug 2008 23:52:42 +0000 Subject: [PATCH] * 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! --- src/Client/GUI/DrawObjMgr.cpp | 9 +++ src/Client/GUI/DrawObjMgr.h | 1 + src/Client/GUI/DrawObject.cpp | 4 +- src/Client/GUI/DrawObject.h | 1 + src/Client/GUI/Scene.h | 4 + src/Client/GUI/SceneWorld.cpp | 126 ++++++++++++++++++++++++++----- src/Client/World/MovementMgr.cpp | 7 ++ src/shared/ByteBuffer.h | 82 ++++++++++++++++++++ 8 files changed, 213 insertions(+), 21 deletions(-) diff --git a/src/Client/GUI/DrawObjMgr.cpp b/src/Client/GUI/DrawObjMgr.cpp index 773a0a3..e79a5d8 100644 --- a/src/Client/GUI/DrawObjMgr.cpp +++ b/src/Client/GUI/DrawObjMgr.cpp @@ -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; +} + diff --git a/src/Client/GUI/DrawObjMgr.h b/src/Client/GUI/DrawObjMgr.h index 0bb15ad..202da95 100644 --- a/src/Client/GUI/DrawObjMgr.h +++ b/src/Client/GUI/DrawObjMgr.h @@ -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; diff --git a/src/Client/GUI/DrawObject.cpp b/src/Client/GUI/DrawObject.cpp index 32eb6b7..52f3129 100644 --- a/src/Client/GUI/DrawObject.cpp +++ b/src/Client/GUI/DrawObject.cpp @@ -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()) diff --git a/src/Client/GUI/DrawObject.h b/src/Client/GUI/DrawObject.h index 5555545..7da06ae 100644 --- a/src/Client/GUI/DrawObject.h +++ b/src/Client/GUI/DrawObject.h @@ -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: diff --git a/src/Client/GUI/Scene.h b/src/Client/GUI/Scene.h index 5f90e95..8f9e642 100644 --- a/src/Client/GUI/Scene.h +++ b/src/Client/GUI/Scene.h @@ -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; }; diff --git a/src/Client/GUI/SceneWorld.cpp b/src/Client/GUI/SceneWorld.cpp index 02ed3d7..6398adf 100644 --- a/src/Client/GUI/SceneWorld.cpp +++ b/src/Client/GUI/SceneWorld.cpp @@ -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& nodelist = smgr->getRootSceneNode()->getChildren(); + for(core::list::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; +} + diff --git a/src/Client/World/MovementMgr.cpp b/src/Client/World/MovementMgr.cpp index bdb33c8..39f6518 100644 --- a/src/Client/World/MovementMgr.cpp +++ b/src/Client/World/MovementMgr.cpp @@ -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. } diff --git a/src/shared/ByteBuffer.h b/src/shared/ByteBuffer.h index 4d16c3c..07c3f8b 100644 --- a/src/shared/ByteBuffer.h +++ b/src/shared/ByteBuffer.h @@ -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(a) < 32) || (read(a) > 126)) + printf("."); + else + printf("%c", read(a)); + } + printf("|\r\n"); + line++; + printf("|"); + } + printf("%02x ", read(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(a) < 32) || (read(a) > 126)) + printf("."); + else + printf("%c", read(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(a) < 32) || (read(a) > 126)) + printf("."); + else + printf("%c", read(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 ByteBuffer &operator>>(ByteBuffer &b, std::map } return b; } + #endif