actorid
Nicolay Korslund 15 years ago
commit 91e8590288

@ -13,12 +13,15 @@ set(GAMEREND
mwrender/mwscene.cpp
mwrender/cellimp.cpp
mwrender/interior.cpp
mwrender/exterior.cpp
mwrender/playerpos.cpp
mwrender/sky.cpp)
set(GAMEREND_HEADER
mwrender/cell.hpp
mwrender/cellimp.hpp
mwrender/mwscene.hpp
mwrender/interior.hpp
mwrender/exterior.hpp
mwrender/playerpos.hpp
mwrender/sky.hpp)
source_group(apps\\openmw\\mwrender FILES ${GAMEREND} ${GAMEREND_HEADER})

@ -21,9 +21,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -21,9 +21,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -33,9 +33,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -29,9 +29,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -28,7 +28,7 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
@ -40,7 +40,7 @@ namespace MWClass
const float radius = float (ref->base->data.radius);
cellRender.insertLight (r, g, b, radius);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -40,7 +40,8 @@ namespace MWClass
std::string headModel = "meshes\\" +
environment.mWorld->getStore().bodyParts.find(headID)->model;
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh (headModel);
//TODO: define consts for each bodypart e.g. chest, foot, wrist... and put the parts in the
@ -51,7 +52,7 @@ namespace MWClass
if (bodyPart)
cellRender.insertMesh("meshes\\" + bodyPart->model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
void Npc::enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -19,9 +19,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -24,9 +24,9 @@ namespace MWClass
const std::string &model = ref->base->model;
if (!model.empty())
{
cellRender.insertBegin (ref->ref);
MWRender::Rendering rendering (cellRender, ref->ref);
cellRender.insertMesh ("meshes\\" + model);
ref->mData.setHandle (cellRender.insertEnd (ref->mData.isEnabled()));
ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
}
}

@ -1,6 +1,8 @@
#include "cellimp.hpp"
#include <cassert>
#include <iostream>
#include <exception>
#include "../mwworld/class.hpp"
#include "../mwworld/ptr.hpp"
@ -23,8 +25,16 @@ void insertCellRefList (CellRenderImp& cellRender, MWWorld::Environment& environ
{
MWWorld::Ptr ptr (&*it, &cell);
class_.insertObj (ptr, cellRender, environment);
class_.enable (ptr, environment);
try
{
class_.insertObj (ptr, cellRender, environment);
class_.enable (ptr, environment);
}
catch (const std::exception& e)
{
std::string error ("error during rendering: ");
std::cerr << error + e.what() << std::endl;
}
}
}
}

@ -43,6 +43,38 @@ namespace MWRender
void insertCell(ESMS::CellStore<MWWorld::RefData> &cell, MWWorld::Environment& environment);
};
/// Exception-safe rendering
class Rendering
{
CellRenderImp& mCellRender;
bool mEnd;
// not implemented
Rendering (const Rendering&);
Rendering& operator= (const Rendering&);
public:
Rendering (CellRenderImp& cellRender, ESM::CellRef &ref)
: mCellRender (cellRender), mEnd (false)
{
mCellRender.insertBegin (ref);
}
~Rendering()
{
if (!mEnd)
mCellRender.insertEnd (false);
}
std::string end (bool enable)
{
assert (!mEnd);
mEnd = true;
return mCellRender.insertEnd (enable);
}
};
}
#endif

@ -0,0 +1,241 @@
#include "exterior.hpp"
#include <OgreEntity.h>
#include <OgreLight.h>
#include <OgreSceneNode.h>
#include <OgreCamera.h>
#include <OgreSceneManager.h>
#include <components/nifogre/ogre_nif_loader.hpp>
#include "mwscene.hpp"
using namespace MWRender;
using namespace Ogre;
using namespace ESMS;
bool ExteriorCellRender::lightConst = false;
float ExteriorCellRender::lightConstValue = 0.0f;
bool ExteriorCellRender::lightLinear = true;
int ExteriorCellRender::lightLinearMethod = 1;
float ExteriorCellRender::lightLinearValue = 3;
float ExteriorCellRender::lightLinearRadiusMult = 1;
bool ExteriorCellRender::lightQuadratic = false;
int ExteriorCellRender::lightQuadraticMethod = 2;
float ExteriorCellRender::lightQuadraticValue = 16;
float ExteriorCellRender::lightQuadraticRadiusMult = 1;
bool ExteriorCellRender::lightOutQuadInLin = false;
// start inserting a new reference.
void ExteriorCellRender::insertBegin (ESM::CellRef &ref)
{
assert (!insert);
// Create and place scene node for this object
insert = base->createChildSceneNode();
const float *f = ref.pos.pos;
insert->setPosition(f[0], f[1], f[2]);
insert->setScale(ref.scale, ref.scale, ref.scale);
// Convert MW rotation to a quaternion:
f = ref.pos.rot;
// Rotate around X axis
Quaternion xr(Radian(-f[0]), Vector3::UNIT_X);
// Rotate around Y axis
Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y);
// Rotate around Z axis
Quaternion zr(Radian(-f[2]), Vector3::UNIT_Z);
// Rotates first around z, then y, then x
insert->setOrientation(xr*yr*zr);
}
// insert a mesh related to the most recent insertBegin call.
void ExteriorCellRender::insertMesh(const std::string &mesh)
{
assert (insert);
NIFLoader::load(mesh);
MovableObject *ent = scene.getMgr()->createEntity(mesh);
insert->attachObject(ent);
}
// insert a light related to the most recent insertBegin call.
void ExteriorCellRender::insertLight(float r, float g, float b, float radius)
{
assert (insert);
Ogre::Light *light = scene.getMgr()->createLight();
light->setDiffuseColour (r, g, b);
float cval=0.0f, lval=0.0f, qval=0.0f;
if(lightConst)
cval = lightConstValue;
if(!lightOutQuadInLin)
{
if(lightLinear)
radius *= lightLinearRadiusMult;
if(lightQuadratic)
radius *= lightQuadraticRadiusMult;
if(lightLinear)
lval = lightLinearValue / pow(radius, lightLinearMethod);
if(lightQuadratic)
qval = lightQuadraticValue / pow(radius, lightQuadraticMethod);
}
else
{
// FIXME:
// Do quadratic or linear, depending if we're in an exterior or interior
// cell, respectively. Ignore lightLinear and lightQuadratic.
}
light->setAttenuation(10*radius, cval, lval, qval);
insert->attachObject(light);
}
// finish inserting a new reference and return a handle to it.
std::string ExteriorCellRender::insertEnd (bool enable)
{
assert (insert);
std::string handle = insert->getName();
if (!enable)
insert->setVisible (false);
insert = 0;
return handle;
}
// configure lighting according to cell
void ExteriorCellRender::configureAmbient()
{
ambientColor.setAsABGR (cell.cell->ambi.ambient);
setAmbientMode();
// Create a "sun" that shines light downwards. It doesn't look
// completely right, but leave it for now.
Ogre::Light *light = scene.getMgr()->createLight();
Ogre::ColourValue colour;
colour.setAsABGR (cell.cell->ambi.sunlight);
light->setDiffuseColour (colour);
light->setType(Ogre::Light::LT_DIRECTIONAL);
light->setDirection(0,-1,0);
}
// configure fog according to cell
void ExteriorCellRender::configureFog()
{
Ogre::ColourValue color;
color.setAsABGR (cell.cell->ambi.fog);
float high = 4500 + 9000 * (1-cell.cell->ambi.fogDensity);
float low = 200;
scene.getMgr()->setFog (FOG_LINEAR, color, 0, low, high);
scene.getCamera()->setFarClipDistance (high + 10);
scene.getViewport()->setBackgroundColour (color);
}
void ExteriorCellRender::setAmbientMode()
{
switch (ambientMode)
{
case 0:
scene.getMgr()->setAmbientLight(ambientColor);
break;
case 1:
scene.getMgr()->setAmbientLight(0.7f*ambientColor + 0.3f*ColourValue(1,1,1));
break;
case 2:
scene.getMgr()->setAmbientLight(ColourValue(1,1,1));
break;
}
}
void ExteriorCellRender::show()
{
base = scene.getRoot()->createChildSceneNode();
configureAmbient();
configureFog();
insertCell(cell, mEnvironment);
}
void ExteriorCellRender::hide()
{
if(base)
base->setVisible(false);
}
void ExteriorCellRender::destroy()
{
if(base)
{
base->removeAndDestroyAllChildren();
scene.getMgr()->destroySceneNode(base);
}
base = NULL;
}
// Switch through lighting modes.
void ExteriorCellRender::toggleLight()
{
if (ambientMode==2)
ambientMode = 0;
else
++ambientMode;
switch (ambientMode)
{
case 0: std::cout << "Setting lights to normal\n"; break;
case 1: std::cout << "Turning the lights up\n"; break;
case 2: std::cout << "Turning the lights to full\n"; break;
}
setAmbientMode();
}
void ExteriorCellRender::enable (const std::string& handle)
{
if (!handle.empty())
scene.getMgr()->getSceneNode (handle)->setVisible (true);
}
void ExteriorCellRender::disable (const std::string& handle)
{
if (!handle.empty())
scene.getMgr()->getSceneNode (handle)->setVisible (false);
}
void ExteriorCellRender::deleteObject (const std::string& handle)
{
if (!handle.empty())
{
Ogre::SceneNode *node = scene.getMgr()->getSceneNode (handle);
node->removeAndDestroyAllChildren();
scene.getMgr()->destroySceneNode (node);
}
}

@ -0,0 +1,114 @@
#ifndef _GAME_RENDER_EXTERIOR_H
#define _GAME_RENDER_EXTERIOR_H
#include "cell.hpp"
#include "cellimp.hpp"
#include "OgreColourValue.h"
namespace Ogre
{
class SceneNode;
}
namespace MWWorld
{
class Environment;
}
namespace MWRender
{
class MWScene;
/**
This class is responsible for inserting meshes and other
rendering objects from the given cell into the given rendering
scene.
*/
class ExteriorCellRender : public CellRender, private CellRenderImp
{
static bool lightConst;
static float lightConstValue;
static bool lightLinear;
static int lightLinearMethod;
static float lightLinearValue;
static float lightLinearRadiusMult;
static bool lightQuadratic;
static int lightQuadraticMethod;
static float lightQuadraticValue;
static float lightQuadraticRadiusMult;
static bool lightOutQuadInLin;
ESMS::CellStore<MWWorld::RefData> &cell;
MWWorld::Environment &mEnvironment;
MWScene &scene;
/// The scene node that contains all objects belonging to this
/// cell.
Ogre::SceneNode *base;
Ogre::SceneNode *insert;
// 0 normal, 1 more bright, 2 max
int ambientMode;
Ogre::ColourValue ambientColor;
/// start inserting a new reference.
virtual void insertBegin (ESM::CellRef &ref);
/// insert a mesh related to the most recent insertBegin call.
virtual void insertMesh(const std::string &mesh);
/// insert a light related to the most recent insertBegin call.
virtual void insertLight(float r, float g, float b, float radius);
/// finish inserting a new reference and return a handle to it.
virtual std::string insertEnd (bool Enable);
/// configure lighting according to cell
void configureAmbient();
/// configure fog according to cell
void configureFog();
void setAmbientMode();
public:
ExteriorCellRender(ESMS::CellStore<MWWorld::RefData> &_cell, MWWorld::Environment& environment,
MWScene &_scene)
: cell(_cell), mEnvironment (environment), scene(_scene), base(NULL), insert(NULL), ambientMode (0) {}
virtual ~ExteriorCellRender() { destroy(); }
/// Make the cell visible. Load the cell if necessary.
virtual void show();
/// Remove the cell from rendering, but don't remove it from
/// memory.
virtual void hide();
/// Destroy all rendering objects connected with this cell.
virtual void destroy(); // comment by Zini: shouldn't this go into the destructor?
/// Switch through lighting modes.
void toggleLight();
/// Make the reference with the given handle visible.
virtual void enable (const std::string& handle);
/// Make the reference with the given handle invisible.
virtual void disable (const std::string& handle);
/// Remove the reference with the given handle permanently from the scene.
virtual void deleteObject (const std::string& handle);
};
}
#endif

@ -24,8 +24,6 @@ namespace MWRender
This class is responsible for inserting meshes and other
rendering objects from the given cell into the given rendering
scene.
TODO FIXME: Doesn't do full cleanup yet.
*/
class InteriorCellRender : public CellRender, private CellRenderImp

@ -9,6 +9,10 @@
#include "OgreCamera.h"
#include "OgreTextureManager.h"
#include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone
#include "../mwworld/ptr.hpp"
#include <components/esm/loadstat.hpp>
using namespace MWRender;
using namespace Ogre;
@ -36,7 +40,7 @@ MWScene::MWScene(OEngine::Render::OgreRenderer &_rend)
mRaySceneQuery = rend.getScene()->createRayQuery(Ray());
}
std::pair<std::string, float> MWScene::getFacedHandle()
std::pair<std::string, float> MWScene::getFacedHandle (MWWorld::World& world)
{
std::string handle = "";
float distance = -1;
@ -57,10 +61,14 @@ std::pair<std::string, float> MWScene::getFacedHandle()
{
// there seem to be omnipresent objects like the caelum sky dom,
// the distance of these objects is always 0 so this if excludes these
// TODO: Check if the object can be focused (ignore walls etc..
// in this state of openmw not possible)
if ( itr->movable && itr->distance >= 0.1)
{
// horrible hack to exclude statics. this must be removed as soon as a replacement for the
// AABB raycasting is implemented (we should not ignore statics)
MWWorld::Ptr ptr = world.getPtrViaHandle (itr->movable->getParentSceneNode()->getName());
if (ptr.getType()==typeid (ESM::Static))
break;
if ( nearest == result.end() ) //if no object is set
{
nearest = itr;
@ -80,4 +88,3 @@ std::pair<std::string, float> MWScene::getFacedHandle()
return std::pair<std::string, float>(handle, distance);
}

@ -13,6 +13,11 @@ namespace Ogre
class RaySceneQuery;
}
namespace MWWorld
{
class World;
}
namespace MWRender
{
/** Class responsible for Morrowind-specific interfaces to OGRE.
@ -43,7 +48,7 @@ namespace MWRender
//pair<name, distance>
//name is empty and distance = -1 if there is no object which
//can be faced
std::pair<std::string, float> getFacedHandle();
std::pair<std::string, float> getFacedHandle (MWWorld::World& world);
};
}

@ -0,0 +1,18 @@
#include "playerpos.hpp"
#include "../mwworld/world.hpp"
namespace MWRender
{
void PlayerPos::setPos(float x, float y, float z, bool updateCamera)
{
mWorld.moveObject (getPlayer(), x, y, z);
if (updateCamera)
camera->setPosition (Ogre::Vector3 (
mPlayer.ref.pos.pos[0],
mPlayer.ref.pos.pos[2],
-mPlayer.ref.pos.pos[1]));
}
}

@ -8,6 +8,11 @@
#include "../mwworld/refdata.hpp"
#include "../mwworld/ptr.hpp"
namespace MWWorld
{
class World;
}
namespace MWRender
{
// This class keeps track of the player position. It takes care of
@ -18,31 +23,19 @@ namespace MWRender
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> mPlayer;
MWWorld::Ptr::CellStore *mCellStore;
Ogre::Camera *camera;
MWWorld::World& mWorld;
public:
PlayerPos(Ogre::Camera *cam, const ESM::NPC *player) :
mCellStore (0), camera(cam)
PlayerPos(Ogre::Camera *cam, const ESM::NPC *player, MWWorld::World& world) :
mCellStore (0), camera(cam), mWorld (world)
{
mPlayer.base = player;
mPlayer.ref.pos.pos[0] = mPlayer.ref.pos.pos[1] = mPlayer.ref.pos.pos[2] = 0;
}
// Set the player position. Uses Morrowind coordinates.
void setPos(float _x, float _y, float _z, bool updateCamera = false)
{
mPlayer.ref.pos.pos[0] = _x;
mPlayer.ref.pos.pos[1] = _y;
mPlayer.ref.pos.pos[2] = _z;
void setPos(float _x, float _y, float _z, bool updateCamera = false);
if (updateCamera)
camera->setPosition (Ogre::Vector3 (
mPlayer.ref.pos.pos[0],
mPlayer.ref.pos.pos[2],
mPlayer.ref.pos.pos[1]));
// TODO: Update sound listener
}
void setCell (MWWorld::Ptr::CellStore *cellStore)
{
mCellStore = cellStore;
@ -54,7 +47,6 @@ namespace MWRender
// orientation. After the call, the new position is returned.
void moveRel(float &relX, float &relY, float &relZ)
{
// TODO: Update mPlayer state
using namespace Ogre;
// Move camera relative to its own direction
@ -75,7 +67,7 @@ namespace MWRender
// Set the position
setPos(relX, relY, relZ);
}
MWWorld::Ptr getPlayer()
{
MWWorld::Ptr ptr (&mPlayer, mCellStore);

@ -18,50 +18,79 @@ namespace MWScript
class OpCellChanged : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context
= static_cast<InterpreterContext&> (runtime.getContext());
runtime.push (context.getWorld().hasCellChanged() ? 1 : 0);
}
}
};
class OpCOC : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context
= static_cast<InterpreterContext&> (runtime.getContext());
std::string cell = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
runtime.pop();
ESM::Position pos;
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
context.getWorld().changeCell (cell, pos);
}
}
};
class OpCOE : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
InterpreterContext& context
= static_cast<InterpreterContext&> (runtime.getContext());
Interpreter::Type_Integer x = runtime[0].mInteger;
runtime.pop();
Interpreter::Type_Integer y = runtime[0].mInteger;
runtime.pop();
ESM::Position pos;
context.getWorld().indexToPosition (x, y, pos.pos[0], pos.pos[1]);
pos.pos[2] = 0;
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
context.getWorld().changeToExteriorCell (pos);
}
};
const int opcodeCellChanged = 0x2000000;
const int opcodeCOC = 0x2000026;
const int opcodeCOE = 0x200007c;
void registerExtensions (Compiler::Extensions& extensions)
{
extensions.registerFunction ("cellchanged", 'l', "", opcodeCellChanged);
extensions.registerInstruction ("coc", "S", opcodeCOC);
extensions.registerInstruction ("centeroncell", "S", opcodeCOC);
extensions.registerInstruction ("coe", "ll", opcodeCOE);
extensions.registerInstruction ("centeronexterior", "ll", opcodeCOE);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
{
interpreter.installSegment5 (opcodeCellChanged, new OpCellChanged);
interpreter.installSegment5 (opcodeCOC, new OpCOC);
interpreter.installSegment5 (opcodeCOE, new OpCOE);
}
}
}

@ -88,6 +88,10 @@ op 0x2000078: GetItemCount
op 0x2000079: GetItemCount, explicit reference
op 0x200007a: RemoveItem
op 0x200007b: RemoveItem, explicit reference
<<<<<<< HEAD:apps/openmw/mwscript/docs/vmformat.txt
op 0x200007c: COC
opcodes 0x200007d-0x3ffffff unused
=======
op 0x200007c: GetAiPackageDone
op 0x200007d: GetAiPackageDone, explicit reference
op 0x200007e-0x2000084: Enable Controls
@ -95,3 +99,4 @@ op 0x2000085-0x200008b: Disable Controls
op 0x200008c: Unlock
op 0x200008d: Unlock, explicit reference
opcodes 0x200008e-0x3ffffff unused
>>>>>>> master:apps/openmw/mwscript/docs/vmformat.txt

@ -13,6 +13,9 @@ namespace MWWorld
void ActionTeleportPlayer::execute (Environment& environment)
{
environment.mWorld->changeCell (mCellName, mPosition);
if (mCellName.empty())
environment.mWorld->changeToExteriorCell (mPosition);
else
environment.mWorld->changeCell (mCellName, mPosition);
}
}

@ -17,6 +17,7 @@ namespace MWWorld
public:
ActionTeleportPlayer (const std::string& cellName, const ESM::Position& position);
///< If cellName is empty, an exterior cell is asumed.
virtual void execute (Environment& environment);
};

@ -8,6 +8,7 @@
#include "../mwrender/sky.hpp"
#include "../mwrender/interior.hpp"
#include "../mwrender/exterior.hpp"
#include "../mwmechanics/mechanicsmanager.hpp"
@ -249,6 +250,66 @@ namespace MWWorld
throw std::runtime_error ("month out of range");
}
void World::removeScripts (Ptr::CellStore *cell)
{
ScriptList::iterator iter = mLocalScripts.begin();
while (iter!=mLocalScripts.end())
{
if (iter->second.getCell()==cell)
mLocalScripts.erase (iter++);
else
++iter;
}
}
void World::unloadCell (CellRenderCollection::iterator iter)
{
removeScripts (iter->first);
mEnvironment.mMechanicsManager->dropActors (iter->first);
iter->second->destroy();
mEnvironment.mSoundManager->stopSound (iter->first);
delete iter->second;
mActiveCells.erase (iter);
}
void World::loadCell (Ptr::CellStore *cell, MWRender::CellRender *render)
{
// register local scripts
insertInteriorScripts (*cell);
// This connects the cell data with the rendering scene.
std::pair<CellRenderCollection::iterator, bool> result =
mActiveCells.insert (std::make_pair (cell, render));
if (result.second)
{
// Load the cell and insert it into the renderer
result.first->second->show();
}
}
void World::playerCellChange (Ptr::CellStore *cell, const ESM::Position& position)
{
mPlayerPos->setPos (position.pos[0], position.pos[1], position.pos[2], true);
mPlayerPos->setCell (cell);
// TODO orientation
mEnvironment.mMechanicsManager->addActor (mPlayerPos->getPlayer());
mEnvironment.mMechanicsManager->watchActor (mPlayerPos->getPlayer());
}
void World::adjustSky()
{
if (mSky)
{
toggleSky();
// TODO set weather
toggleSky();
}
}
World::World (OEngine::Render::OgreRenderer& renderer, const boost::filesystem::path& dataDir,
const std::string& master, bool newGame, Environment& environment)
: mSkyManager (0), mScene (renderer), mPlayerPos (0), mCurrentCell (0), mGlobalVariables (0),
@ -263,7 +324,7 @@ namespace MWWorld
mEsm.open (masterPath.file_string());
mStore.load (mEsm);
mPlayerPos = new MWRender::PlayerPos (mScene.getCamera(), mStore.npcs.find ("player"));
mPlayerPos = new MWRender::PlayerPos (mScene.getCamera(), mStore.npcs.find ("player"), *this);
// global variables
mGlobalVariables = new Globals (mStore);
@ -522,57 +583,114 @@ namespace MWWorld
void World::changeCell (const std::string& cellName, const ESM::Position& position)
{
// remove active
CellRenderCollection::iterator active = mActiveCells.begin();
while (active!=mActiveCells.end())
{
unloadCell (active++);
}
// Load cell.
mInteriors[cellName].loadInt (cellName, mStore, mEsm);
Ptr::CellStore *cell = &mInteriors[cellName];
loadCell (cell, new MWRender::InteriorCellRender (*cell, mEnvironment, mScene));
// adjust player
mCurrentCell = cell;
playerCellChange (cell, position);
// Sky system
adjustSky();
mCellChanged = true;
}
void World::changeCell (int X, int Y, const ESM::Position& position)
{
// remove active
CellRenderCollection::iterator active = mActiveCells.begin();
if (active!=mActiveCells.end())
while (active!=mActiveCells.end())
{
mEnvironment.mMechanicsManager->dropActors (active->first);
active->second->destroy();
mEnvironment.mSoundManager->stopSound (active->first);
delete active->second;
mActiveCells.erase (active);
if (!(active->first->cell->data.flags & ESM::Cell::Interior))
{
if (std::abs (X-active->first->cell->data.gridX)<=1 &&
std::abs (Y-active->first->cell->data.gridY)<=1)
{
// keep cells within the new 3x3 grid
++active;
continue;
}
}
unloadCell (active++);
}
// register local scripts
mLocalScripts.clear(); // FIXME won't work with exteriors
insertInteriorScripts (*cell);
// Load cells
for (int x=X-1; x<=X+1; ++x)
for (int y=Y-1; y<=Y+1; ++y)
{
CellRenderCollection::iterator iter = mActiveCells.begin();
// adjust player
mPlayerPos->setPos (position.pos[0], position.pos[1], position.pos[2], true);
mPlayerPos->setCell (cell);
// TODO orientation
while (iter!=mActiveCells.end())
{
assert (!(iter->first->cell->data.flags & ESM::Cell::Interior));
// This connects the cell data with the rendering scene.
std::pair<CellRenderCollection::iterator, bool> result =
mActiveCells.insert (std::make_pair (cell,
new MWRender::InteriorCellRender (*cell, mEnvironment, mScene)));
if (x==iter->first->cell->data.gridX &&
y==iter->first->cell->data.gridY)
break;
if (result.second)
++iter;
}
if (iter==mActiveCells.end())
{
mExteriors[std::make_pair (x, y)].loadExt (x, y, mStore, mEsm);
Ptr::CellStore *cell = &mExteriors[std::make_pair (x, y)];
loadCell (cell, new MWRender::ExteriorCellRender (*cell, mEnvironment, mScene));
}
}
// find current cell
CellRenderCollection::iterator iter = mActiveCells.begin();
while (iter!=mActiveCells.end())
{
// Load the cell and insert it into the renderer
result.first->second->show();
assert (!(iter->first->cell->data.flags & ESM::Cell::Interior));
if (X==iter->first->cell->data.gridX &&
Y==iter->first->cell->data.gridY)
break;
++iter;
}
// Actors
mEnvironment.mMechanicsManager->addActor (mPlayerPos->getPlayer());
mEnvironment.mMechanicsManager->watchActor (mPlayerPos->getPlayer());
assert (iter!=mActiveCells.end());
mCurrentCell = iter->first;
// adjust player
playerCellChange (&mExteriors[std::make_pair (X, Y)], position);
// Sky system
if (mSky)
{
toggleSky();
// TODO set weather
toggleSky();
}
adjustSky();
mCellChanged = true;
}
void World::changeToExteriorCell (const ESM::Position& position)
{
int x = 0;
int y = 0;
positionToIndex (position.pos[0], position.pos[1], x, y);
changeCell (x, y, position);
}
void World::markCellAsUnchanged()
{
mCellChanged = false;
@ -580,7 +698,7 @@ namespace MWWorld
std::string World::getFacedHandle()
{
std::pair<std::string, float> result = mScene.getFacedHandle();
std::pair<std::string, float> result = mScene.getFacedHandle (*this);
if (result.first.empty() ||
result.second>getStore().gameSettings.find ("iMaxActivateDist")->i)
@ -608,4 +726,56 @@ namespace MWWorld
}
}
}
void World::moveObject (Ptr ptr, float x, float y, float z)
{
ptr.getCellRef().pos.pos[0] = x;
ptr.getCellRef().pos.pos[1] = y;
ptr.getCellRef().pos.pos[2] = z;
if (ptr==mPlayerPos->getPlayer())
{
if (mCurrentCell)
{
if (!(mCurrentCell->cell->data.flags & ESM::Cell::Interior))
{
// exterior -> adjust loaded cells
int cellX = 0;
int cellY = 0;
positionToIndex (x, y, cellX, cellY);
if (mCurrentCell->cell->data.gridX!=cellX || mCurrentCell->cell->data.gridY!=cellY)
{
changeCell (cellX, cellY, mPlayerPos->getPlayer().getCellRef().pos);
}
}
}
}
// TODO cell change for non-player ref
}
void World::indexToPosition (int cellX, int cellY, float &x, float &y) const
{
const int cellSize = 8192;
x = cellSize * cellX;
y = cellSize * cellY;
}
void World::positionToIndex (float x, float y, int &cellX, int &cellY) const
{
const int cellSize = 8192;
cellX = static_cast<int> (x/cellSize);
if (x<0)
--cellX;
cellY = static_cast<int> (y/cellSize);
if (y<0)
--cellY;
}
}

@ -41,7 +41,7 @@ namespace MWWorld
{
public:
typedef std::vector<std::pair<std::string, Ptr> > ScriptList;
typedef std::list<std::pair<std::string, Ptr> > ScriptList;
private:
@ -56,6 +56,7 @@ namespace MWWorld
ESM::ESMReader mEsm;
ESMS::ESMStore mStore;
std::map<std::string, Ptr::CellStore> mInteriors;
std::map<std::pair<int, int>, Ptr::CellStore> mExteriors;
ScriptList mLocalScripts;
MWWorld::Globals *mGlobalVariables;
bool mSky;
@ -76,6 +77,16 @@ namespace MWWorld
int getDaysPerMonth (int month) const;
void removeScripts (Ptr::CellStore *cell);
void unloadCell (CellRenderCollection::iterator iter);
void loadCell (Ptr::CellStore *cell, MWRender::CellRender *render);
void playerCellChange (Ptr::CellStore *cell, const ESM::Position& position);
void adjustSky();
public:
World (OEngine::Render::OgreRenderer& renderer, const boost::filesystem::path& master,
@ -130,12 +141,24 @@ namespace MWWorld
void changeCell (const std::string& cellName, const ESM::Position& position);
///< works only for interior cells currently.
void changeCell (int X, int Y, const ESM::Position& position);
void changeToExteriorCell (const ESM::Position& position);
void markCellAsUnchanged();
std::string getFacedHandle();
///< Return handle of the object the player is looking at
void deleteObject (Ptr ptr);
void moveObject (Ptr ptr, float x, float y, float z);
void indexToPosition (int cellX, int cellY, float &x, float &y) const;
///< Convert cell numbers to position.
void positionToIndex (float x, float y, int &cellX, int &cellY) const;
///< Convert position to cell numbers
};
}

@ -123,7 +123,14 @@ namespace ESMS
/** Ditto for exterior cell. */
void loadExt(int X, int Y, const ESMStore &store, ESMReader &esm)
{
std::cout << "loading exterior cell '" << X << ", " << Y << "'\n";
cell = store.cells.searchExt (X, Y);
if(cell == NULL)
throw std::runtime_error("Exterior cell not found");
loadRefs(store, esm);
}
private:

@ -194,6 +194,21 @@ namespace ESMS
return it->second;
}
const Cell *searchExt (int x, int y) const
{
ExtCells::const_iterator it = extCells.find (x);
if (it==extCells.end())
return 0;
ExtCellsCol::const_iterator it2 = it->second.find (y);
if (it2 == it->second.end())
return 0;
return it2->second;
}
void load(ESMReader &esm, const std::string &id)
{
using namespace std;

Loading…
Cancel
Save