mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 06:53:52 +00:00
very early implementation of exterior rendering
This commit is contained in:
parent
6583b66e82
commit
0111631ee9
8 changed files with 469 additions and 15 deletions
|
@ -13,12 +13,14 @@ set(GAMEREND
|
|||
mwrender/mwscene.cpp
|
||||
mwrender/cellimp.cpp
|
||||
mwrender/interior.cpp
|
||||
mwrender/exterior.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})
|
||||
|
|
241
apps/openmw/mwrender/exterior.cpp
Normal file
241
apps/openmw/mwrender/exterior.cpp
Normal 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);
|
||||
}
|
||||
}
|
114
apps/openmw/mwrender/exterior.hpp
Normal file
114
apps/openmw/mwrender/exterior.hpp
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,4 +83,5 @@ op 0x2000078: GetItemCount
|
|||
op 0x2000079: GetItemCount, explicit reference
|
||||
op 0x200007a: RemoveItem
|
||||
op 0x200007b: RemoveItem, explicit reference
|
||||
opcodes 0x200007c-0x3ffffff unused
|
||||
op 0x200007c: COC
|
||||
opcodes 0x200007d-0x3ffffff unused
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "../mwrender/sky.hpp"
|
||||
#include "../mwrender/interior.hpp"
|
||||
#include "../mwrender/exterior.hpp"
|
||||
|
||||
#include "../mwmechanics/mechanicsmanager.hpp"
|
||||
|
||||
|
@ -573,6 +574,69 @@ namespace MWWorld
|
|||
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()
|
||||
{
|
||||
mCellChanged = false;
|
||||
|
|
|
@ -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;
|
||||
|
@ -130,6 +131,10 @@ 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();
|
||||
|
|
Loading…
Reference in a new issue