1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-20 09:53:51 +00:00

very early implementation of exterior rendering

This commit is contained in:
Marc Zinnschlag 2010-08-20 13:33:03 +02:00
parent 6583b66e82
commit 0111631ee9
8 changed files with 469 additions and 15 deletions

View file

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

View file

@ -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);
}
}

View file

@ -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

View file

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

View file

@ -47,21 +47,50 @@ namespace MWScript
} }
}; };
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();
const int cellSize = 8192;
ESM::Position pos;
pos.pos[0] = cellSize * x;
pos.pos[1] = cellSize * y;
pos.pos[2] = 0;
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
context.getWorld().changeToExteriorCell (pos);
}
};
const int opcodeCellChanged = 0x2000000; const int opcodeCellChanged = 0x2000000;
const int opcodeCOC = 0x2000026; const int opcodeCOC = 0x2000026;
const int opcodeCOE = 0x200007c;
void registerExtensions (Compiler::Extensions& extensions) void registerExtensions (Compiler::Extensions& extensions)
{ {
extensions.registerFunction ("cellchanged", 'l', "", opcodeCellChanged); extensions.registerFunction ("cellchanged", 'l', "", opcodeCellChanged);
extensions.registerInstruction ("coc", "S", opcodeCOC); extensions.registerInstruction ("coc", "S", opcodeCOC);
extensions.registerInstruction ("centeroncell", "S", opcodeCOC); extensions.registerInstruction ("centeroncell", "S", opcodeCOC);
extensions.registerInstruction ("coe", "ll", opcodeCOE);
extensions.registerInstruction ("centeronexterior", "ll", opcodeCOE);
} }
void installOpcodes (Interpreter::Interpreter& interpreter) void installOpcodes (Interpreter::Interpreter& interpreter)
{ {
interpreter.installSegment5 (opcodeCellChanged, new OpCellChanged); interpreter.installSegment5 (opcodeCellChanged, new OpCellChanged);
interpreter.installSegment5 (opcodeCOC, new OpCOC); interpreter.installSegment5 (opcodeCOC, new OpCOC);
interpreter.installSegment5 (opcodeCOE, new OpCOE);
} }
} }
} }

View file

@ -83,4 +83,5 @@ op 0x2000078: GetItemCount
op 0x2000079: GetItemCount, explicit reference op 0x2000079: GetItemCount, explicit reference
op 0x200007a: RemoveItem op 0x200007a: RemoveItem
op 0x200007b: RemoveItem, explicit reference op 0x200007b: RemoveItem, explicit reference
opcodes 0x200007c-0x3ffffff unused op 0x200007c: COC
opcodes 0x200007d-0x3ffffff unused

View file

@ -8,6 +8,7 @@
#include "../mwrender/sky.hpp" #include "../mwrender/sky.hpp"
#include "../mwrender/interior.hpp" #include "../mwrender/interior.hpp"
#include "../mwrender/exterior.hpp"
#include "../mwmechanics/mechanicsmanager.hpp" #include "../mwmechanics/mechanicsmanager.hpp"
@ -573,6 +574,69 @@ namespace MWWorld
mCellChanged = true; mCellChanged = true;
} }
void World::changeCell (int X, int Y, const ESM::Position& position)
{
// Load cell.
mExteriors[std::make_pair (X, Y)].loadExt (X, Y, mStore, mEsm);
Ptr::CellStore *cell = &mExteriors[std::make_pair (X, Y)];
// remove active
CellRenderCollection::iterator active = mActiveCells.begin();
if (active!=mActiveCells.end())
{
mEnvironment.mMechanicsManager->dropActors (active->first);
active->second->destroy();
mEnvironment.mSoundManager->stopSound (active->first);
delete active->second;
mActiveCells.erase (active);
}
// register local scripts
mLocalScripts.clear(); // FIXME won't work with exteriors
insertInteriorScripts (*cell);
// adjust player
mPlayerPos->setPos (position.pos[0], position.pos[1], position.pos[2], true);
mPlayerPos->setCell (cell);
// TODO orientation
// This connects the cell data with the rendering scene.
std::pair<CellRenderCollection::iterator, bool> result =
mActiveCells.insert (std::make_pair (cell,
new MWRender::ExteriorCellRender (*cell, mEnvironment, mScene)));
if (result.second)
{
// Load the cell and insert it into the renderer
result.first->second->show();
}
// Actors
mEnvironment.mMechanicsManager->addActor (mPlayerPos->getPlayer());
mEnvironment.mMechanicsManager->watchActor (mPlayerPos->getPlayer());
// Sky system
if (mSky)
{
toggleSky();
// TODO set weather
toggleSky();
}
mCellChanged = true;
}
void World::changeToExteriorCell (const ESM::Position& position)
{
const int cellSize = 8192;
int x = static_cast<int> (position.pos[0] / cellSize);
int y = static_cast<int> (position.pos[1] / cellSize);
changeCell (x, y, position);
}
void World::markCellAsUnchanged() void World::markCellAsUnchanged()
{ {
mCellChanged = false; mCellChanged = false;

View file

@ -56,6 +56,7 @@ namespace MWWorld
ESM::ESMReader mEsm; ESM::ESMReader mEsm;
ESMS::ESMStore mStore; ESMS::ESMStore mStore;
std::map<std::string, Ptr::CellStore> mInteriors; std::map<std::string, Ptr::CellStore> mInteriors;
std::map<std::pair<int, int>, Ptr::CellStore> mExteriors;
ScriptList mLocalScripts; ScriptList mLocalScripts;
MWWorld::Globals *mGlobalVariables; MWWorld::Globals *mGlobalVariables;
bool mSky; bool mSky;
@ -130,6 +131,10 @@ namespace MWWorld
void changeCell (const std::string& cellName, const ESM::Position& position); void changeCell (const std::string& cellName, const ESM::Position& position);
///< works only for interior cells currently. ///< works only for interior cells currently.
void changeCell (int X, int Y, const ESM::Position& position);
void changeToExteriorCell (const ESM::Position& position);
void markCellAsUnchanged(); void markCellAsUnchanged();
std::string getFacedHandle(); std::string getFacedHandle();