diff --git a/.gitignore b/.gitignore index 05511a424..322375a54 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +screenshot*.png *.o *~ data diff --git a/CMakeLists.txt b/CMakeLists.txt index 63d03ec0a..16380bc26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,35 +10,45 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) set(BSA bsa/bsa_archive.cpp bsa/bsa_file.cpp) set(BSA_HEADER bsa/bsa_archive.hpp bsa/bsa_file.hpp) +source_group(bsa FILES ${BSA} ${BSA_HEADER}) set(NIF nif/nif_file.cpp) set(NIF_HEADER nif/controlled.hpp nif/effect.hpp nif/nif_types.hpp nif/record.hpp nif/controller.hpp nif/extra.hpp nif/node.hpp nif/record_ptr.hpp nif/data.hpp nif/nif_file.hpp nif/property.hpp) +source_group(nif FILES ${NIF} ${NIF_HEADER}) set(NIFOGRE nifogre/ogre_nif_loader.cpp) set(NIFOGRE_HEADER nifogre/ogre_nif_loader.hpp) +source_group(nifogre FILES ${NIFOGRE} ${NIFOGRE_HEADER}) set(TOOLS tools/stringops.cpp tools/fileops.cpp) set(TOOLS_HEADER tools/fileops.hpp tools/slice_array.hpp tools/stringops.hpp) +source_group(tools FILES ${TOOLS} ${TOOLS_HEADER}) set(MANGLE_VFS mangle/vfs/servers/ogre_vfs.cpp) +source_group(mangle_vfs FILES ${MANGLE_VFS}) set(OGRE ogre/renderer.cpp) set(OGRE_HEADER ogre/renderer.hpp) +source_group(ogre FILES ${OGRE} ${OGRE_HEADER}) set(INPUT input/oismanager.cpp) -set(INPUT_HEADER input/oismanager.hpp input/listener.hpp input/func_binder.hpp input/dispatch_map.hpp input/dispatcher.hpp) +set(INPUT_HEADER input/oismanager.hpp input/listener.hpp input/func_binder.hpp input/dispatch_map.hpp input/dispatcher.hpp input/poller.hpp) +source_group(input FILES ${INPUT} ${INPUT_HEADER}) -set(GAME game/main.cpp) -set(GAME_HEADER game/mwinput/inputmanager.hpp) +set(GAME game/main.cpp game/engine.cpp) +set(GAME_HEADER game/mwinput/inputmanager.hpp game/engine.hpp) +source_group(game FILES ${GAME} ${GAME_HEADER}) set(ESM_STORE esm_store/store.cpp esm_store/cell_store.cpp) set(ESM_STORE_HEADER esm_store/cell_store.hpp esm_store/reclists.hpp esm_store/store.hpp) +source_group(esm_store FILES ${ESM_STORE} ${ESM_STORE_HEADER}) set(GAMEREND game/mwrender/mwscene.cpp game/mwrender/cell.cpp game/mwrender/interior.cpp) set(GAMEREND_HEADER game/mwrender/cell.hpp game/mwrender/mwscene.hpp - game/mwrender/interior.hpp) + game/mwrender/interior.hpp game/mwrender/playerpos.hpp) +source_group(game_renderer FILES ${GAMEREND} ${GAMEREND_HEADER}) set(ESM_HEADER esm/defs.hpp esm/loadcell.hpp esm/loadfact.hpp esm/loadltex.hpp esm/loadskil.hpp @@ -50,6 +60,7 @@ set(ESM_HEADER esm/defs.hpp esm/loadcell.hpp esm/loadfact.hpp esm/loadltex.hpp esm/loadbody.hpp esm/loaddial.hpp esm/loadlevlist.hpp esm/loadrace.hpp esm/loadweap.hpp esm/loadbook.hpp esm/loaddoor.hpp esm/loadligh.hpp esm/loadregn.hpp esm/records.hpp esm/loadbsgn.hpp esm/loadench.hpp esm/loadlocks.hpp esm/loadscpt.hpp) +source_group(esm_header FILES ${ESM_HEADER}) # Platform specific if (WIN32) diff --git a/esm/loadalch.hpp b/esm/loadalch.hpp index 7fc649b45..a556350b0 100644 --- a/esm/loadalch.hpp +++ b/esm/loadalch.hpp @@ -26,7 +26,7 @@ struct Potion void load(ESMReader &esm) { model = esm.getHNString("MODL"); - icon = esm.getHNString("TEXT"); // not ITEX here for some reason + icon = esm.getHNOString("TEXT"); // not ITEX here for some reason script = esm.getHNOString("SCRI"); name = esm.getHNOString("FNAM"); esm.getHNT(data, "ALDT", 12); diff --git a/esm/loadcell.hpp b/esm/loadcell.hpp index dcb255949..c4641a57b 100644 --- a/esm/loadcell.hpp +++ b/esm/loadcell.hpp @@ -11,8 +11,9 @@ namespace ESM { loading process, but are rather loaded later on demand when we are setting up a specific cell. */ -struct CellRef +class CellRef { +public: int refnum; // Reference number std::string refID; // ID of object being referenced diff --git a/esm/loadlevlist.hpp b/esm/loadlevlist.hpp index 046fd91ef..8b0ae45b2 100644 --- a/esm/loadlevlist.hpp +++ b/esm/loadlevlist.hpp @@ -60,7 +60,7 @@ struct LeveledListBase // items. Also, some times we don't want to merge lists, just // overwrite. Figure out a way to give the user this option. - for(int i=0; i + +#include + +#include "esm_store/cell_store.hpp" +#include "bsa/bsa_archive.hpp" +#include "ogre/renderer.hpp" +#include "tools/fileops.hpp" + +#include "mwrender/interior.hpp" +#include "mwinput/inputmanager.hpp" +#include "mwrender/playerpos.hpp" + +OMW::Engine::Engine() {} + +// adjust name and load bsa + +void OMW::Engine::prepareMaster() +{ + std::string::size_type sep = mMaster.find_last_of ("."); + + if (sep==std::string::npos) + { + mMaster += ".esm"; + } +} + +// Load all BSA files in data directory. + +void OMW::Engine::loadBSA() +{ + boost::filesystem::directory_iterator end; + + for (boost::filesystem::directory_iterator iter (mDataDir); iter!=end; ++iter) + { + if (boost::filesystem::extension (iter->path())==".bsa") + { + std::cout << "Adding " << iter->path().string() << std::endl; + addBSA(iter->path().file_string()); + } + } +} + +// add resources directory +// \note This function works recursively. + +void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) +{ + mOgre.getRoot()->addResourceLocation (path.file_string(), "FileSystem", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); +} + +// Set data dir + +void OMW::Engine::setDataDir (const boost::filesystem::path& dataDir) +{ + mDataDir = boost::filesystem::system_complete (dataDir); +} + +// Set start cell name (only interiors for now) + +void OMW::Engine::setCell (const std::string& cellName) +{ + mCellName = cellName; +} + +// Set master file (esm) +// - If the given name does not have an extension, ".esm" is added automatically +// - Currently OpenMW only supports one master at the same time. + +void OMW::Engine::addMaster (const std::string& master) +{ + assert (mMaster.empty()); + mMaster = master; +} + +// Initialise and enter main loop. + +void OMW::Engine::go() +{ + assert (!mDataDir.empty()); + assert (!mCellName.empty()); + assert (!mMaster.empty()); + + std::cout << "Hello, fellow traveler!\n"; + + std::cout << "Your data directory for today is: " << mDataDir << "\n"; + + std::cout << "Initializing OGRE\n"; + + const char* plugCfg = "plugins.cfg"; + + mOgre.configure(!isFile("ogre.cfg"), plugCfg, false); + + addResourcesDirectory (mDataDir / "Meshes"); + addResourcesDirectory (mDataDir / "Textures"); + + prepareMaster(); + loadBSA(); + + boost::filesystem::path masterPath (mDataDir); + masterPath /= mMaster; + + std::cout << "Loading ESM " << masterPath.string() << "\n"; + ESM::ESMReader esm; + ESMS::ESMStore store; + ESMS::CellStore cell; + + // This parses the ESM file and loads a sample cell + esm.open(masterPath.file_string()); + store.load(esm); + + cell.loadInt(mCellName, store, esm); + + // Create the window + mOgre.createWindow("OpenMW"); + + std::cout << "\nSetting up cell rendering\n"; + + // Sets up camera, scene manager, and viewport. + MWRender::MWScene scene(mOgre); + + // Used to control the player camera and position + MWRender::PlayerPos player(scene.getCamera()); + + // This connects the cell data with the rendering scene. + MWRender::InteriorCellRender rend(cell, scene); + + // Load the cell and insert it into the renderer + rend.show(); + + std::cout << "Setting up input system\n"; + + // Sets up the input system + MWInput::MWInputManager input(mOgre, player); + + std::cout << "\nStart! Press Q/ESC or close window to exit.\n"; + + // Start the main rendering loop + mOgre.start(); + + std::cout << "\nThat's all for now!\n"; +} + diff --git a/game/engine.hpp b/game/engine.hpp new file mode 100644 index 000000000..fb6ddbbe4 --- /dev/null +++ b/game/engine.hpp @@ -0,0 +1,55 @@ +#ifndef ENGINE_H +#define ENGINE_H + +#include + +#include + +#include "mwrender/mwscene.hpp" + +namespace OMW +{ + /// \brief Main engine class, that brings together all the components of OpenMW + + class Engine + { + boost::filesystem::path mDataDir; + Render::OgreRenderer mOgre; + std::string mCellName; + std::string mMaster; + + // not implemented + Engine (const Engine&); + Engine& operator= (const Engine&); + + /// adjust name and load bsa + void prepareMaster(); + + /// add resources directory + /// \note This function works recursively. + void addResourcesDirectory (const boost::filesystem::path& path); + + /// Load all BSA files in data directory. + void loadBSA(); + + public: + + Engine(); + + /// Set data dir + void setDataDir (const boost::filesystem::path& dataDir); + + /// Set start cell name (only interiors for now) + void setCell (const std::string& cellName); + + /// Set master file (esm) + /// - If the given name does not have an extension, ".esm" is added automatically + /// - Currently OpenMW only supports one master at the same time. + void addMaster (const std::string& master); + + /// Initialise and enter main loop. + void go(); + }; +} + +#endif diff --git a/game/main.cpp b/game/main.cpp index 24ea7c453..477e4aba9 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -3,94 +3,30 @@ #include #include -#include "boost/program_options.hpp" +#include -#include "esm_store/cell_store.hpp" -#include "bsa/bsa_archive.hpp" -#include "ogre/renderer.hpp" -#include "tools/fileops.hpp" - -#include "mwrender/interior.hpp" -#include "mwrender/mwscene.hpp" -#include "mwinput/inputmanager.hpp" +#include "engine.hpp" using namespace std; -void maintest (std::string dataDir, const std::string& cellName) -{ - assert (!dataDir.empty()); - - if (dataDir[dataDir.size()-1]!='/' && dataDir[dataDir.size()-1]!='\\') - dataDir += "/"; - - const char* esmFile = "Morrowind.esm"; - const char* bsaFile = "Morrowind.bsa"; - - const char* plugCfg = "plugins.cfg"; - - cout << "Hello, fellow traveler!\n"; - - cout << "Your data directory for today is: " << dataDir << "\n"; - - cout << "Initializing OGRE\n"; - Render::OgreRenderer ogre; - ogre.configure(!isFile("ogre.cfg"), plugCfg, false); - - cout << "Adding " << bsaFile << endl; - addBSA(dataDir + bsaFile); - - cout << "Loading ESM " << esmFile << "\n"; - ESM::ESMReader esm; - ESMS::ESMStore store; - ESMS::CellStore cell; - - // This parses the ESM file and loads a sample cell - esm.open(dataDir + esmFile); - store.load(esm); - - cell.loadInt(cellName, store, esm); - - // Create the window - ogre.createWindow("OpenMW"); - - cout << "\nSetting up cell rendering\n"; - - // Sets up camera, scene manager etc - MWRender::MWScene scene(ogre); - - // This connects the cell data with the rendering scene. - MWRender::InteriorCellRender rend(cell, scene); - - // Load the cell and insert it into the renderer - rend.show(); +/// Parse command line options and openmw.cfg file (if one exists). Results are directly +/// written to \a engine. +/// \return Run OpenMW? - cout << "Setting up input system\n"; - - // Sets up the input system - MWInput::MWInputManager input(ogre); - - cout << "\nStart! Press Q/ESC or close window to exit.\n"; - - // Start the main rendering loop - ogre.start(); - - cout << "\nThat's all for now!\n"; -} - -int main(int argc, char**argv) +bool parseOptions (int argc, char**argv, OMW::Engine& engine) { - try - { boost::program_options::options_description desc ( - "Syntax: openmw \nAllowed options"); + "Syntax: openmw \nAllowed options"); desc.add_options() - ("help", "print help message") - ("data", boost::program_options::value()->default_value ("data"), - "set data directory") - ("start", boost::program_options::value()->default_value ("Beshara"), - "set initial cell (only interior cells supported at the moment") - ; + ("help", "print help message") + ("data", boost::program_options::value()->default_value ("data"), + "set data directory") + ("start", boost::program_options::value()->default_value ("Beshara"), + "set initial cell (only interior cells supported at the moment") + ("master", boost::program_options::value()->default_value ("Morrowind"), + "master file") + ; boost::program_options::variables_map variables; @@ -101,24 +37,45 @@ int main(int argc, char**argv) boost::program_options::store(valid_opts, variables); boost::program_options::notify(variables); + /* + boost::program_options::store ( + boost::program_options::parse_command_line (argc, argv, desc), variables); + boost::program_options::notify (variables); + */ if (configFile.is_open()) - boost::program_options::store ( - boost::program_options::parse_config_file (configFile, desc), variables); + boost::program_options::store ( + boost::program_options::parse_config_file (configFile, desc), variables); if (variables.count ("help")) { - std::cout << desc << std::endl; + std::cout << desc << std::endl; + return false; } - else - { - maintest (variables["data"].as(), variables["start"].as()); - } - } - catch(exception &e) + + engine.setDataDir (variables["data"].as()); + engine.setCell (variables["start"].as()); + engine.addMaster (variables["master"].as()); + + return true; +} + +int main(int argc, char**argv) +{ + try { - cout << "\nERROR: " << e.what() << endl; - return 1; + OMW::Engine engine; + + if (parseOptions (argc, argv, engine)) + { + engine.go(); + } + } + catch(exception &e) + { + cout << "\nERROR: " << e.what() << endl; + return 1; } - return 0; + + return 0; } diff --git a/game/mwinput/inputmanager.hpp b/game/mwinput/inputmanager.hpp index eeee5cf82..5c2c9857f 100644 --- a/game/mwinput/inputmanager.hpp +++ b/game/mwinput/inputmanager.hpp @@ -1,9 +1,12 @@ -#ifndef _INPUT_MWINPUTMANAGER_H -#define _INPUT_MWINPUTMANAGER_H +#ifndef _MWINPUT_MWINPUTMANAGER_H +#define _MWINPUT_MWINPUTMANAGER_H #include "input/listener.hpp" #include "input/dispatcher.hpp" +#include "input/poller.hpp" #include "boost/bind.hpp" +#include "game/mwrender/playerpos.hpp" +#include "platform/strings.h" namespace MWInput { @@ -11,33 +14,118 @@ namespace MWInput { A_Quit, // Exit the program + A_Screenshot, // Take a screenshot + + A_MoveLeft, // Move player left / right + A_MoveRight, + A_MoveUp, // Move up / down + A_MoveDown, + A_MoveForward, // Forward / Backward + A_MoveBackward, + A_LAST // Marker for the last item }; // Class that handles all input and key bindings for OpenMW - class MWInputManager + class MWInputManager : public Ogre::FrameListener { + // Note: the order here is important. The OISManager must be + // initialized before poller and listener. Input::Dispatcher disp; + Render::OgreRenderer &ogre; Input::OISManager input; + Input::Poller poller; Input::InputListener listener; + MWRender::PlayerPos &player; + + // Count screenshots. TODO: We should move this functionality to + // OgreRender or somewhere else. + int shotCount; + + // Write screenshot to file. + void screenshot() + { + // Find the first unused filename. + // + char buf[50]; + do + { + snprintf(buf, 50, "screenshot%03d.png", shotCount++); + } while (boost::filesystem::exists(buf)); + + ogre.screenshot(buf); + } public: - MWInputManager(Render::OgreRenderer &ogre) + MWInputManager(Render::OgreRenderer &_ogre, + MWRender::PlayerPos &_player) : disp(A_LAST), - input(ogre), - listener(ogre, input, disp) + ogre(_ogre), + input(_ogre), + poller(input), + listener(_ogre, input, disp), + player(_player), + shotCount(0) { using namespace Input; using namespace OIS; // Bind MW-specific functions - disp.funcs.bind(A_Quit, - boost::bind(&InputListener::exitNow, &listener), + disp.funcs.bind(A_Quit, boost::bind(&InputListener::exitNow, &listener), "Quit program"); + disp.funcs.bind(A_Screenshot, boost::bind(&MWInputManager::screenshot, this), + "Screenshot"); + + // Add ourselves as a frame listener, to catch movement keys + ogre.getRoot()->addFrameListener(this); + + // Tell the input listener about the camera + listener.setCamera(player.getCamera()); // Key bindings disp.bind(KC_Q, A_Quit); disp.bind(KC_ESCAPE, A_Quit); + disp.bind(KC_SYSRQ, A_Screenshot); + + // Key bindings for polled keys + + // Arrow keys + poller.bind(A_MoveLeft, KC_LEFT); + poller.bind(A_MoveRight, KC_RIGHT); + poller.bind(A_MoveForward, KC_UP); + poller.bind(A_MoveBackward, KC_DOWN); + + // WASD keys + poller.bind(A_MoveLeft, KC_A); + poller.bind(A_MoveRight, KC_D); + poller.bind(A_MoveForward, KC_W); + poller.bind(A_MoveBackward, KC_S); + + // Use shift and ctrl for up and down + poller.bind(A_MoveUp, KC_LSHIFT); + poller.bind(A_MoveDown, KC_LCONTROL); + } + + // Used to check for movement keys + bool frameStarted(const Ogre::FrameEvent &evt) + { + float speed = 300 * evt.timeSinceLastFrame; + float moveX = 0, moveY = 0, moveZ = 0; + + if(poller.isDown(A_MoveLeft)) moveX -= speed; + if(poller.isDown(A_MoveRight)) moveX += speed; + if(poller.isDown(A_MoveForward)) moveZ -= speed; + if(poller.isDown(A_MoveBackward)) moveZ += speed; + + // TODO: These should be enabled for floating modes (like + // swimming and levitation) and disabled for everything else. + if(poller.isDown(A_MoveUp)) moveY += speed; + if(poller.isDown(A_MoveDown)) moveY -= speed; + + if(moveX != 0 || moveY != 0 || moveZ != 0) + player.moveRel(moveX, moveY, moveZ); + + return true; } }; } diff --git a/game/mwrender/cell.cpp b/game/mwrender/cell.cpp index dfbe6bbb5..396e24cf5 100644 --- a/game/mwrender/cell.cpp +++ b/game/mwrender/cell.cpp @@ -29,13 +29,14 @@ void insertObj(CellRender& cellRender, const ESMS::LiveCellRef& live cellRender.insertBegin (liveRef.ref); cellRender.insertMesh ("meshes\\" + model); - - int color = liveRef.base->data.color; - - cellRender.insertLight(color & 255, - (color >> 8) & 255, - (color >> 16) & 255, - liveRef.base->data.radius); + + // Extract the color and convert to floating point + const int color = liveRef.base->data.color; + const float r = ((color >> 0) & 0xFF) / 255.0f; + const float g = ((color >> 8) & 0xFF) / 255.0f; + const float b = ((color >> 16) & 0xFF) / 255.0f; + const float radius = float(liveRef.base->data.radius); + cellRender.insertLight(r, g, b, radius); cellRender.insertEnd(); } diff --git a/game/mwrender/interior.cpp b/game/mwrender/interior.cpp index 22c39423e..684e7cf63 100644 --- a/game/mwrender/interior.cpp +++ b/game/mwrender/interior.cpp @@ -156,7 +156,7 @@ void InteriorCellRender::setAmbientMode() case 1: - scene.getMgr()->setAmbientLight(0.7*ambientColor + 0.3*ColourValue(1,1,1)); + scene.getMgr()->setAmbientLight(0.7f*ambientColor + 0.3f*ColourValue(1,1,1)); break; case 2: diff --git a/game/mwrender/playerpos.hpp b/game/mwrender/playerpos.hpp new file mode 100644 index 000000000..cf1d02092 --- /dev/null +++ b/game/mwrender/playerpos.hpp @@ -0,0 +1,58 @@ +#ifndef _MWRENDER_PLAYERPOS_H +#define _MWRENDER_PLAYERPOS_H + +#include "OgreCamera.h" + +namespace MWRender +{ + // This class keeps track of the player position. It takes care of + // camera movement, sound listener updates, and collision handling + // (to be done). + class PlayerPos + { + float x, y, z; + Ogre::Camera *camera; + + public: + PlayerPos(Ogre::Camera *cam) : + camera(cam), x(0), y(0), z(0) {} + + // Set the player position. Uses Morrowind coordinates. + void setPos(float _x, float _y, float _z) + { + x = _x; + y = _y; + z = _z; + + // TODO: Update sound listener + } + + Ogre::Camera *getCamera() { return camera; } + + // Move the player relative to her own position and + // orientation. After the call, the new position is returned. + void moveRel(float &relX, float &relY, float &relZ) + { + using namespace Ogre; + + // Move camera relative to its own direction + camera->moveRelative(Vector3(relX,0,relZ)); + + // Up/down movement is always done relative the world axis. + camera->move(Vector3(0,relY,0)); + + // Get new camera position, converting back to MW coords. + Vector3 pos = camera->getPosition(); + relX = pos[0]; + relY = -pos[2]; + relZ = pos[1]; + + // TODO: Collision detection must be used to find the REAL new + // position. + + // Set the position + setPos(relX, relY, relZ); + } + }; +} +#endif diff --git a/input/func_binder.hpp b/input/func_binder.hpp index b70650202..20119b07b 100644 --- a/input/func_binder.hpp +++ b/input/func_binder.hpp @@ -54,7 +54,8 @@ public: */ void bind(int index, Action action, const std::string &name="") { - assert(index >= 0 && index < bindings.size()); + assert(index >= 0 && index < (int)bindings.size()); + FuncBinding &fb = bindings[index]; fb.action = action; fb.name = name; @@ -65,7 +66,8 @@ public: */ void unbind(int index) { - assert(index >= 0 && index < bindings.size()); + assert(index >= 0 && index < (int)bindings.size()); + bindings[index] = FuncBinding(); } @@ -75,7 +77,8 @@ public: */ void call(int index, const void *p=NULL) const { - assert(index >= 0 && index < bindings.size()); + assert(index >= 0 && index < (int)bindings.size()); + const FuncBinding &fb = bindings[index]; if(fb.action) fb.action(index, p); } @@ -83,14 +86,16 @@ public: /// Check if a given index is bound to anything bool isBound(int index) const { - assert(index >= 0 && index < bindings.size()); + assert(index >= 0 && index < (int)bindings.size()); + return !bindings[index].action.empty(); } /// Return the name associated with an action (empty if not bound) const std::string &getName(int index) const { - assert(index >= 0 && index < bindings.size()); + assert(index >= 0 && index < (int)bindings.size()); + return bindings[index].name; } }; diff --git a/input/listener.hpp b/input/listener.hpp index 38f899215..5b9d4fb49 100644 --- a/input/listener.hpp +++ b/input/listener.hpp @@ -24,12 +24,17 @@ namespace Input mMouse = input.mouse; mKeyboard = input.keyboard; + assert(mKeyboard); + assert(mWindow); + // Add ourself to the managers rend.getRoot() -> addFrameListener(this); mKeyboard -> setEventCallback(this); mMouse -> setEventCallback(this); } + void setCamera(Ogre::Camera *cam) { camera = cam; } + // Call this to exit the main loop void exitNow() { doExit = true; } @@ -59,6 +64,29 @@ namespace Input bool mouseMoved( const OIS::MouseEvent &arg ) { + using namespace Ogre; + assert(camera); + + // Mouse sensitivity. Should be a config option later. + const float MS = 0.2f; + + float x = arg.state.X.rel * MS; + float y = arg.state.Y.rel * MS; + + camera->yaw(Degree(-x)); + + // The camera before pitching + Quaternion nopitch = camera->getOrientation(); + + camera->pitch(Degree(-y)); + + // Apply some failsafe measures against the camera flipping + // upside down. Is the camera close to pointing straight up or + // down? + if(camera->getUp()[1] <= 0.1) + // If so, undo the last pitch + camera->setOrientation(nopitch); + return true; } @@ -76,6 +104,7 @@ namespace Input const Dispatcher &disp; Ogre::RenderWindow *mWindow; + Ogre::Camera *camera; OIS::Mouse *mMouse; OIS::Keyboard *mKeyboard; bool doExit; diff --git a/input/oismanager.cpp b/input/oismanager.cpp index 07714da3f..92495f967 100644 --- a/input/oismanager.cpp +++ b/input/oismanager.cpp @@ -30,8 +30,9 @@ OISManager::OISManager(Render::OgreRenderer &rend) windowHndStr << windowHnd; pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str())); - // Non-exclusive mouse and keyboard input in debug mode - if(true) + // Non-exclusive mouse and keyboard input in debug mode. Debug mode + // isn't implemented yet though. + if(false) { #if defined OIS_WIN32_PLATFORM pl.insert(std::make_pair(std::string("w32_mouse"), diff --git a/input/poller.hpp b/input/poller.hpp new file mode 100644 index 000000000..e7d712b35 --- /dev/null +++ b/input/poller.hpp @@ -0,0 +1,51 @@ +#ifndef _INPUT_POLLER_H +#define _INPUT_POLLER_H + +#include "dispatch_map.hpp" +#include "oismanager.hpp" + +namespace Input { + +/** The poller is used to check (poll) for keys rather than waiting + for events. TODO: Might make this OIS-independent later. */ +struct Poller +{ + DispatchMap map; + OIS::Keyboard *keyboard; + + Poller(Input::OISManager &ois) + { + keyboard = ois.keyboard; + assert(keyboard); + } + + /** Bind or unbind a given action with a key. The action is the first + parameter, the key is the second. + */ + void bind(int in, int out) { map.bind(in, out); } + void unbind(int in, int out) { map.unbind(in, out); } + bool isBound(int in) const { return map.isBound(in); } + + /// Check whether a given action button is currently pressed. + typedef DispatchMap::OutList _O; + bool isDown(int index) const + { + assert(keyboard); + + // No bindings, no action + if(!isBound(index)) + return false; + + // Get all the keys bound to this action, and check them. + const _O &list = map.getList(index); + _O::const_iterator it; + for(it = list.begin(); it != list.end(); it++) + // If there's any match, we're good to go. + if(keyboard->isKeyDown((OIS::KeyCode)*it)) return true; + + return false; + } +}; + +} +#endif diff --git a/nifogre/ogre_nif_loader.cpp b/nifogre/ogre_nif_loader.cpp index a7a887c24..de00b443f 100644 --- a/nifogre/ogre_nif_loader.cpp +++ b/nifogre/ogre_nif_loader.cpp @@ -30,10 +30,14 @@ #include "nif/node.hpp" #include "nif/data.hpp" #include "nif/property.hpp" +#include "platform/strings.h" // For warning messages #include +// float infinity +#include + typedef unsigned char ubyte; using namespace std; @@ -58,6 +62,78 @@ static void warn(const string &msg) cout << "WARNING (NIF:" << errName << "): " << msg << endl; } +// Helper class that computes the bounding box and of a mesh +class BoundsFinder +{ + struct MaxMinFinder + { + float max, min; + + MaxMinFinder() + { + min = numeric_limits::infinity(); + max = -min; + } + + void add(float f) + { + if(f > max) max = f; + if(f < min) min = f; + } + + // Return Max(max**2, min**2) + float getMaxSquared() + { + float m1 = max*max; + float m2 = min*min; + if(m1 >= m2) return m1; + return m2; + } + }; + + MaxMinFinder X, Y, Z; + +public: + // Add 'verts' vertices to the calculation. The 'data' pointer is + // expected to point to 3*verts floats representing x,y,z for each + // point. + void add(float *data, int verts) + { + for(int i=0;i OGRE. Not in use yet. static SceneBlendFactor getBlendFactor(int mode) { @@ -177,10 +253,6 @@ static void createMaterial(const String &name, // make sure that all materials are given unique names. static String getUniqueName(const String &input) { -#ifdef WIN32 -#define snprintf _snprintf -#endif - static int addon = 0; static char buf[8]; snprintf(buf, 8, "_%d", addon++); @@ -296,6 +368,22 @@ static void createOgreMesh(Mesh *mesh, NiTriShape *shape, const String &material // Set material if one was given if(!material.empty()) sub->setMaterialName(material); + + /* Old commented D code. Might be useful when reimplementing + animation. + // Assign this submesh to the given bone + VertexBoneAssignment v; + v.boneIndex = ((Bone*)bone)->getHandle(); + v.weight = 1.0; + + std::cerr << "+ Assigning bone index " << v.boneIndex << "\n"; + + for(int i=0; i < numVerts; i++) + { + v.vertexIndex = i; + sub->addBoneAssignment(v); + } + */ } // Helper math functions. Reinventing linear algebra for the win! @@ -341,8 +429,10 @@ static void vectorMul(const Matrix &A, float *C) C[i] = a*A.v[i].array[0] + b*A.v[i].array[1] + c*A.v[i].array[2]; } -static void handleNiTriShape(Mesh *mesh, NiTriShape *shape, int flags) +static void handleNiTriShape(Mesh *mesh, NiTriShape *shape, int flags, BoundsFinder &bounds) { + assert(shape != NULL); + // Interpret flags bool hidden = (flags & 0x01) != 0; // Not displayed bool collide = (flags & 0x02) != 0; // Use mesh for collision @@ -462,47 +552,53 @@ static void handleNiTriShape(Mesh *mesh, NiTriShape *shape, int flags) alphaFlags, alphaTest, texName); } } - } - - { - /* Do in-place transformation of all the vertices and normals. This - is pretty messy stuff, but we need it to make the sub-meshes - appear in the correct place. Neither Ogre nor Bullet support - nested levels of sub-meshes with transformations applied to each - level. - */ - NiTriShapeData *data = shape->data.getPtr(); - int numVerts = data->vertices.length / 3; + } // End of material block, if(!hidden) ... + + /* Do in-place transformation of all the vertices and normals. This + is pretty messy stuff, but we need it to make the sub-meshes + appear in the correct place. Neither Ogre nor Bullet support + nested levels of sub-meshes with transformations applied to each + level. + */ + NiTriShapeData *data = shape->data.getPtr(); + int numVerts = data->vertices.length / 3; - float *ptr = (float*)data->vertices.ptr; + float *ptr = (float*)data->vertices.ptr; + float *optr = ptr; - // Rotate, scale and translate all the vertices - const Matrix &rot = shape->trafo->rotation; - const Vector &pos = shape->trafo->pos; - float scale = shape->trafo->scale; - for(int i=0; itrafo->rotation; + const Vector &pos = shape->trafo->pos; + float scale = shape->trafo->scale; + for(int i=0; inormals.length) - { - ptr = (float*)data->normals.ptr; - for(int i=0; inormals.length) + { + ptr = (float*)data->normals.ptr; + for(int i=0; itrafo); // For both position and rotation we have that: @@ -550,7 +646,7 @@ static void handleNode(Mesh* mesh, Nif::Node *node, int flags, const Transformat matrixMul(trafo->rotation, final.rotation); // Scalar values are so nice to deal with. Why can't everything - // just be scalars? + // just be scalar? final.scale *= trafo->scale; } @@ -562,12 +658,12 @@ static void handleNode(Mesh* mesh, Nif::Node *node, int flags, const Transformat for(int i=0; itrafo); + handleNode(mesh, &list[i], flags, node->trafo, bounds); } } else if(node->recType == RC_NiTriShape) // For shapes - handleNiTriShape(mesh, (NiTriShape*)node, flags); + handleNiTriShape(mesh, dynamic_cast(node), flags, bounds); } void NIFLoader::loadResource(Resource *resource) @@ -588,6 +684,9 @@ void NIFLoader::loadResource(Resource *resource) return; } + // Helper that computes bounding boxes for us. + BoundsFinder bounds; + // Load the NIF. TODO: Wrap this in a try-catch block once we're out // of the early stages of development. Right now we WANT to catch // every error as early and intrusively as possible, as it's most @@ -604,19 +703,25 @@ void NIFLoader::loadResource(Resource *resource) Record *r = nif.getRecord(0); assert(r != NULL); - if(r->recType != RC_NiNode) + Nif::Node *node = dynamic_cast(r); + + if(node == NULL) { - warn("First record in file was not a NiNode, but a " + + warn("First record in file was not a node, but a " + r->recName.toString() + ". Skipping file."); return; } // Handle the node - handleNode(mesh, (Nif::Node*)r, 0); + handleNode(mesh, node, 0, NULL, bounds); - // Finally, set the bounding value. Just use bogus info right now. - mesh->_setBounds(AxisAlignedBox(-10,-10,-10,10,10,10)); - mesh->_setBoundingSphereRadius(10); + // Finally, set the bounding value. + if(bounds.isValid()) + { + mesh->_setBounds(AxisAlignedBox(bounds.minX(), bounds.minY(), bounds.minZ(), + bounds.maxX(), bounds.maxY(), bounds.maxZ())); + mesh->_setBoundingSphereRadius(bounds.getRadius()); + } } MeshPtr NIFLoader::load(const std::string &name, @@ -632,3 +737,109 @@ MeshPtr NIFLoader::load(const std::string &name, // Nope, create a new one. return MeshManager::getSingleton().createManual(name, group, &g_sing); } + +/* More code currently not in use, from the old D source. This was + used in the first attempt at loading NIF meshes, where each submesh + in the file was given a separate bone in a skeleton. Unfortunately + the OGRE skeletons can't hold more than 256 bones, and some NIFs go + way beyond that. The code might be of use if we implement animated + submeshes like this (the part of the NIF that is animated is + usually much less than the entire file, but the method might still + not be water tight.) + +// Insert a raw RGBA image into the texture system. +extern "C" void ogre_insertTexture(char* name, uint32_t width, uint32_t height, void *data) +{ + TexturePtr texture = TextureManager::getSingleton().createManual( + name, // name + "General", // group + TEX_TYPE_2D, // type + width, height, // width & height + 0, // number of mipmaps + PF_BYTE_RGBA, // pixel format + TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for + // textures updated very often (e.g. each frame) + + // Get the pixel buffer + HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); + + // Lock the pixel buffer and get a pixel box + pixelBuffer->lock(HardwareBuffer::HBL_NORMAL); // for best performance use HBL_DISCARD! + const PixelBox& pixelBox = pixelBuffer->getCurrentLock(); + + void *dest = pixelBox.data; + + // Copy the data + memcpy(dest, data, width*height*4); + + // Unlock the pixel buffer + pixelBuffer->unlock(); +} + +// We need this later for animated meshes. +extern "C" void* ogre_setupSkeleton(char* name) +{ + SkeletonPtr skel = SkeletonManager::getSingleton().create( + name, "Closet", true); + + skel->load(); + + // Create all bones at the origin and unrotated. This is necessary + // since our submeshes each have their own model space. We must + // move the bones after creating an entity, then copy this entity. + return (void*)skel->createBone(); +} + +extern "C" void *ogre_insertBone(char* name, void* rootBone, int32_t index) +{ + return (void*) ( ((Bone*)rootBone)->createChild(index) ); +} +*/ +/* This was the D part: + + // Create a skeleton and get the root bone (index 0) + BonePtr bone = ogre_setupSkeleton(name); + + // Reset the bone index. The next bone to be created has index 1. + boneIndex = 1; + // Create a mesh and assign the skeleton to it + MeshPtr mesh = ogre_setupMesh(name); + + // Loop through the nodes, creating submeshes, materials and + // skeleton bones in the process. + handleNode(node, bone, mesh); + + // Create the "template" entity + EntityPtr entity = ogre_createEntity(name); + + // Loop through once again, this time to set the right + // transformations on the entity's SkeletonInstance. The order of + // children will be the same, allowing us to reference bones using + // their boneIndex. + int lastBone = boneIndex; + boneIndex = 1; + transformBones(node, entity); + if(lastBone != boneIndex) writefln("WARNING: Bone number doesn't match"); + + if(!hasBBox) + ogre_setMeshBoundingBox(mesh, minX, minY, minZ, maxX, maxY, maxZ); + + return entity; +} +void handleNode(Node node, BonePtr root, MeshPtr mesh) +{ + // Insert a new bone for this node + BonePtr bone = ogre_insertBone(node.name, root, boneIndex++); + +} + +void transformBones(Node node, EntityPtr entity) +{ + ogre_transformBone(entity, &node.trafo, boneIndex++); + + NiNode n = cast(NiNode)node; + if(n !is null) + foreach(Node nd; n.children) + transformBones(nd, entity); +} +*/ diff --git a/ogre/renderer.cpp b/ogre/renderer.cpp index a7998596d..61e2478eb 100644 --- a/ogre/renderer.cpp +++ b/ogre/renderer.cpp @@ -15,6 +15,11 @@ void OgreRenderer::cleanup() mRoot = NULL; } +void OgreRenderer::screenshot(const std::string &file) +{ + mWindow->writeContentsToFile(file); +} + bool OgreRenderer::configure(bool showConfig, const std::string &pluginCfg, bool _logging) diff --git a/ogre/renderer.hpp b/ogre/renderer.hpp index 0739aa05a..9f8069ca6 100644 --- a/ogre/renderer.hpp +++ b/ogre/renderer.hpp @@ -42,6 +42,9 @@ namespace Render /// Start the main rendering loop void start() { mRoot->startRendering(); } + /// Write a screenshot to file + void screenshot(const std::string &file); + /// Get the Root Ogre::Root *getRoot() { return mRoot; } diff --git a/old_d_version/input/events.d b/old_d_version/input/events.d index 9273c7129..4c5d570e7 100644 --- a/old_d_version/input/events.d +++ b/old_d_version/input/events.d @@ -57,11 +57,6 @@ import input.ois; bool pause = false; int *guiMode; -void toggleFullscreen() -{ - ogre_toggleFullscreen(); -} - const float volDiff = 0.05; void musVolume(bool increase) @@ -88,16 +83,6 @@ void mainVolume(bool increase) writefln(increase?"Increasing":"Decreasing", " main volume to ", config.getMainVolume); } -void takeScreenShot() -{ - char[] file = format("screenshot_%06d.png", config.screenShotNum++); - ogre_screenshot(toStringz(file)); - writefln("Wrote '%s'", file); -} - -// Mouse sensitivity -float effMX, effMY; - void updateMouseSensitivity() { effMX = *config.mouseSensX; @@ -112,19 +97,6 @@ void togglePause() else writefln("Pause off"); } -extern(C) void d_handleMouseMove(MouseState *state) -{ - debug(printMouseMove) - writefln("handleMouseMove: Abs(%s, %s, %s) Rel(%s, %s, %s)", - state.X.abs, state.Y.abs, state.Z.abs, - state.X.rel, state.Y.rel, state.Z.rel); - - if(*guiMode) return; - - ogre_rotateCamera( state.X.rel * effMX, - state.Y.rel * effMY ); -} - extern(C) void d_handleMouseButton(MouseState *state, int button) { debug(printMouse) diff --git a/old_d_version/input/keys.d b/old_d_version/input/keys.d deleted file mode 100644 index 6799b668f..000000000 --- a/old_d_version/input/keys.d +++ /dev/null @@ -1,272 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (keys.d) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -/* - * This module handles keyboard and mouse button configuration - */ - -module input.keys; - -import std.string; -import std.stdio; - -import input.ois; - -// List of all functions we need to map to keys. If you add new keys, -// REMEMBER to add strings for them below as well. TODO: We should -// redo this entire section so that we insert actual functions into -// the system instead. That way, if we do not insert a function, the -// key gets treated as a "non-event" key. Then we will also force the -// definition of strings and function call to be in the same -// place. The Keys enum can be eliminated, really. Default keysyms can -// be added when the functions are inserted. But don't do anything -// until you know how this will interact with script code. -enum Keys - { - None = 0, - - // Movement - MoveLeft, MoveRight, - TurnLeft, TurnRight, - MoveForward, MoveBackward, - - // Used eg. when flying or swimming - MoveUp, MoveDown, - - // These are handled as events, while the above are not. - FirstEvent, - - // Sound control - MainVolUp, MainVolDown, - MusVolUp, MusVolDown, - SfxVolUp, SfxVolDown, - Mute, - - // These will not be part of the finished product - Fullscreen, - ToggleBattleMusic, - PhysMode, // Toggle physics mode between walking, flying and ghost - Nighteye, // Full ambient lighting - ToggleGui,// Turn the GUI on/off - Console, // Turn console on/off - Debug, - - // Misc - Pause, - ScreenShot, - Exit, - - Length - } - -// List of keyboard-bound functions -char[][] keyToString; - -// Lookup for keyboard key names. TODO: This is currently case -// sensitive, we should use my own AA to fix that. -int[char[]] stringToKeysym; - -// Represents a key binding for a single function. Each function can -// have any number keys bound to it, including mouse buttons. This -// might be extended later to allow joystick buttons and other input -// devices. -struct KeyBind -{ - int syms[]; - - // Does the given keysym match this binding? - bool isMatch(int sym, char ch = 0) - { - assert(sym != 0, "don't send empty syms to isMatch"); - - // We don't match characters yet - if(sym == KC.CharOnly) - return false; - - foreach(s; syms) - if(sym == s) return true; - return false; - } - - // Does any of the given syms match this binding? - bool isMatchArray(int arr[] ...) - { - foreach(i; arr) - if(i!=0 && isMatch(i)) return true; - return false; - } - - // Assign key bindings to this structure. Can be called multiple - // times or with multiple paramters (or an array) to bind multiple - // keys. - void bind(int symlist[] ...) - { - syms ~= symlist; - } - - // Remove all bindings to this function - void clear() - { - syms = null; - } - - // Remove the given syms from this binding, if found. - void remove(int symlist[] ...) - { - foreach(rs; symlist) - // Just loop though all the syms and set matching values to - // zero. isMatch() will ignore zeros. - foreach(ref s; syms) - if(s == rs) s = 0; - } - - // Turn the keysym list into a comma separated list of key names - char[] getString() - { - char[] res = null; - bool notFirst = false; - - foreach(int k; syms) - if(k != 0) // Ignore empty keysyms - { - if(notFirst) res ~= ","; - else notFirst = true; - - res ~= keysymToString[k]; - } - - //writefln("getString returned %s", res); - return res; - } -} - -KeyBindings keyBindings; - -// This structure holds the bindings of all the functions -struct KeyBindings -{ - KeyBind[] bindings; - - // Bind the given function to the given key(s) - void bind(Keys func, char[] key1, char[] key2 = "") - { - bind(func, getSym(key1), getSym(key2)); - } - - void bind(Keys func, int syms[] ...) - { - // Find other bindings that match this key - foreach(int i, ref KeyBind kb; bindings) - if(kb.isMatchArray(syms)) - kb.remove(syms); - bindings[func].bind(syms); - } - - // Find the function that matches the given keysym. We could - // optimize this, but I'm not sure it's worth it. - Keys findMatch(KC keysym, dchar ch) - { - int start=cast(int)Keys.FirstEvent + 1; - foreach(int i, ref KeyBind kb; bindings[start..$]) - if( kb.isMatch(keysym, ch) ) - return cast(Keys)(i+start); - return cast(Keys)0; // No match - } - - static int getSym(char[] key) - { - key = strip(key); - if(key.length) - { - int *p = key in stringToKeysym; - if(p) return *p; - else writefln("Warning: unknown key '%s'", key); - } - return 0; - } - - // Bind a function to a comma-separated key list (intended to be - // used directly with the ini file reader.) - void bindComma(Keys func, char[] keys) - { - int index = keys.find(','); - if(index != -1) - { - // Bind the first in the list - bind(func, keys[0..index]); - // Recurse on the rest - bindComma(func, keys[index+1..$]); - } - // Last or only element in the list - else bind(func, keys); - } - - // Remove all key bindings - void clear() - { - foreach(ref kb; bindings) - kb.clear(); - } - - void initKeys() - { - // Keyboard functions - keyToString.length = Keys.Length; - - keyToString[Keys.MoveLeft] = "Move Left"; - keyToString[Keys.MoveRight] = "Move Right"; - keyToString[Keys.TurnLeft] = "Turn Left"; - keyToString[Keys.TurnRight] = "Turn Right"; - keyToString[Keys.MoveForward] = "Move Forward"; - keyToString[Keys.MoveBackward] = "Move Backward"; - keyToString[Keys.MoveUp] = "Move Up"; - keyToString[Keys.MoveDown] = "Move Down"; - - keyToString[Keys.MainVolUp] = "Increase Main Volume"; - keyToString[Keys.MainVolDown] = "Decrease Main Volume"; - keyToString[Keys.MusVolUp] = "Increase Music Volume"; - keyToString[Keys.MusVolDown] = "Decrease Music Volume"; - keyToString[Keys.SfxVolUp] = "Increase SFX Volume"; - keyToString[Keys.SfxVolDown] = "Decrease SFX Volume"; - keyToString[Keys.Mute] = "Mute Sound"; - - keyToString[Keys.Fullscreen] = "Toggle Fullscreen Mode"; - keyToString[Keys.ToggleBattleMusic] = "Toggle Battle Music"; - keyToString[Keys.PhysMode] = "Toggle Physics Mode"; - keyToString[Keys.Nighteye] = "Toggle Nighteye"; - keyToString[Keys.ToggleGui] = "Toggle GUI"; - keyToString[Keys.Console] = "Console"; - keyToString[Keys.Debug] = "OGRE Test Action"; - - keyToString[Keys.Pause] = "Pause"; - keyToString[Keys.ScreenShot] = "Screen Shot"; - keyToString[Keys.Exit] = "Quick Exit"; - //keyToString[Keys.] = ""; - - bindings.length = Keys.Length; - - // Store all the key strings in a lookup-table - foreach(int k, ref char[] s; keysymToString) - if(s.length) stringToKeysym[s] = k; - } -} diff --git a/old_d_version/ogre/bindings.d b/old_d_version/ogre/bindings.d deleted file mode 100644 index 3d2ce674a..000000000 --- a/old_d_version/ogre/bindings.d +++ /dev/null @@ -1,166 +0,0 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (bindings.d) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -module ogre.bindings; - -import nif.misc; // for Transformation -import ogre.ogre; // for Placement - -import core.resource; - -/* - * This module is the interface to OGRE from D. Since OGRE is written - * in C++, all the code that deals directly with the graphics engine - * is packaged in a bunch of C++ functions. These functions are - * exported from C++ through the C calling convention, and imported - * here. - * - * Note that the C calling convension is not in any way type - * safe. This is convenient, as it allows us to send pointers as one - * type and recieve them as another, without casting, but also - * dangerous since it opens for some nasty bugs. - */ - -// Represents a pointer to a Node in the OGRE engine. We never use -// these directly in D code, only pass them back to the C++ code. -typedef void* NodePtr; - -extern(C): - -// Do engine configuration. Returns 0 if we should continue, 1 if -// not. -int ogre_configure(int showConfig, // Do we show the config dialogue? - char *plugincfg,// Name of 'plugin.cfg' file - int debutOut); // Enable or disable debug output - -// Sets up the window -void ogre_initWindow(); - -// Set up an empty scene. -void ogre_makeScene(); - -// Set the ambient light and "sunlight" -void ogre_setAmbient(float r, float g, float b, - float rs, float gs, float bs); - -// Set fog color and view distance -void ogre_setFog(float rf, float gf, float bf, - float flow, float fhigh); - -// Create a simple sky dome -int ogre_makeSky(); - -// Toggle full ambient lighting on and off -void ogre_toggleLight(); - -// Enter main rendering loop -void ogre_startRendering(); - -// Cleans up after ogre -void ogre_cleanup(); - -// Gets a child SceneNode from the root node, then detatches it to -// hide it from view. Used for creating the "template" node associated -// with a NIF mesh. -NodePtr ogre_getDetachedNode(); - -// Convert a Morrowind rotation (3 floats) to a quaternion (4 floats) -void ogre_mwToQuaternion(float *mw, float *quat); - -// Create a copy of the given scene node, with the given coordinates -// and rotation (as a quaternion.) -NodePtr ogre_insertNode(NodePtr base, char* name, - float *pos, float *quat, float scale); - -// Get the world transformation of a node, returned as a translation -// and a matrix. The matrix includes both rotation and scaling. The -// buffers given must be large enough to store the result (3 and 9 -// floats respectively.) -void ogre_getWorldTransform(NodePtr node, float *trans, float *matrix); - -// Create a (very crappy looking) plane to simulate the water level -void ogre_createWater(float level); - -// Creates a scene node as a child of 'parent', then translates and -// rotates it according to the data in 'trafo'. -NodePtr ogre_createNode( - char *name, // Name to give the node - Transformation *trafo, // Transformation - NodePtr parent, // Parent node - int noRot); // If 1, don't rotate node - -// Create a light with the given diffuse color. Attach it to SceneNode -// 'parent'. -NodePtr ogre_attachLight(char* name, NodePtr parent, - float r, float g, float b, - float radius); - -// Create the specified material -void ogre_createMaterial(char *name, // Name to give resource - float *ambient, // Ambient RBG value - float *diffuse, - float *specular, - float *emissive, // Self illumination - float glossiness,// Same as shininess? - float alpha, // Reflection alpha? - char *texture, // Texture name - int alphaFlags, // Alpha settings (see - ubyte alphaTest);// NiAlphaProperty in nif/) - -// Creates a mesh and gives it a bounding box. Also creates an entity -// and attached it to the given SceneNode 'owner'. -void ogre_createMesh( - char* name, // Name of the mesh - int numVerts, // Number of vertices - float* vertices, // Vertex list - float* normals, // Normal list - float* colors, // Vertex colors - float* uvs, // Texture coordinates - int numFaces, // Number of faces*3 - short* faces, // Faces - float radius, // Bounding sphere - char* material, // Material name, if any - - // Bounding box - float minX,float minY,float minZ, - float maxX,float maxY,float maxZ, - - NodePtr owner // Scene node to attach to. - ); - -// Toggle fullscreen mode -void ogre_toggleFullscreen(); - -// Save a screen shot to the given file name -void ogre_screenshot(char *filename); - -// Camera control and information -void ogre_rotateCamera(float x, float y); -void ogre_moveCamera(float x, float y, float z); -void ogre_setCameraRotation(float r1, float r2, float r3); -void ogre_getCameraPos(float *x, float *y, float *z); -void ogre_getCameraOrientation(float *fx, float *fy, float *fz, float *ux, float *uy, float *uz); -void ogre_moveCameraRel(float x, float y, float z); - -// Insert a raw RGBA image into the texture system. -//void ogre_insertTexture(char *name, int width, int height, void *data); diff --git a/old_d_version/ogre/cpp_framelistener.cpp b/old_d_version/ogre/cpp_framelistener.cpp index 46427a03b..0419c0f7e 100644 --- a/old_d_version/ogre/cpp_framelistener.cpp +++ b/old_d_version/ogre/cpp_framelistener.cpp @@ -1,39 +1,3 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (cpp_framelistener.cpp) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#include - -// Callbacks to D code. - -// Called once each frame -extern "C" int32_t d_frameStarted(float time); - -// Handle events -extern "C" void d_handleKey(int keycode, uint32_t text); -extern "C" void d_handleMouseMove(const OIS::MouseState *state); -extern "C" void d_handleMouseButton(const OIS::MouseState *state, - int32_t button); - // Frame listener, passed to Ogre. The only thing we use this for is // to capture input and pass control to D code. class MorroFrameListener: public FrameListener @@ -128,47 +92,6 @@ public: MorroFrameListener mFrameListener; InputListener mInput; -// Functions called from D during event handling - -extern "C" int32_t ois_isPressed(int32_t keysym) -{ - return mKeyboard->isKeyDown((OIS::KeyCode)keysym); -} - -// Dump screen contents to file -extern "C" void ogre_screenshot(char* filename) -{ - mWindow->writeContentsToFile(filename); - - //This doesn't work, I think I have to set up an overlay or - //something first and display the text manually. - //mWindow->setDebugText(String("Wrote ") + filename); -} - -// Rotate camera as result of mouse movement -extern "C" void ogre_rotateCamera(float x, float y) -{ - mCamera->yaw(Degree(-x)); - - Quaternion nopitch = mCamera->getOrientation(); - - mCamera->pitch(Degree(-y)); - - // Is the camera close to being upside down? - if(mCamera->getUp()[1] <= 0.1) - // If so, undo the last pitch - mCamera->setOrientation(nopitch); -} - -// Get current camera position -extern "C" void ogre_getCameraPos(float *x, float *y, float *z) -{ - Vector3 pos = mCamera->getPosition(); - *x = pos[0]; - *y = -pos[2]; - *z = pos[1]; -} - // Get current camera orientation, in the form of 'front' and 'up' // vectors. extern "C" void ogre_getCameraOrientation(float *fx, float *fy, float *fz, @@ -191,8 +114,6 @@ extern "C" void ogre_moveCamera(float x, float y, float z) // is not affected by the rotation of the root node, so we must // transform this manually. mCamera->setPosition(Vector3(x,z+90,-y)); - - //g_light->setPosition(mCamera->getPosition()); } // Rotate camera using Morrowind rotation specifiers @@ -212,12 +133,3 @@ extern "C" void ogre_setCameraRotation(float r1, float r2, float r3) // Rotates first around z, then y, then x mCamera->setOrientation(xr*yr*zr); } - -// Move camera relative to its own axis set. -extern "C" void ogre_moveCameraRel(float x, float y, float z) -{ - mCamera->moveRelative(Vector3(x,0,z)); - - // up/down movement is always done relative the world axis - mCamera->move(Vector3(0,y,0)); -} diff --git a/old_d_version/ogre/cpp_interface.cpp b/old_d_version/ogre/cpp_interface.cpp index cc68514f0..98df9125e 100644 --- a/old_d_version/ogre/cpp_interface.cpp +++ b/old_d_version/ogre/cpp_interface.cpp @@ -1,96 +1,3 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (cpp_interface.cpp) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -extern "C" Light* ogre_attachLight(char *name, SceneNode* base, - float r, float g, float b, - float radius) -{ - Light *l = mSceneMgr->createLight(name); - l->setDiffuseColour(r,g,b); - - radius /= 4.0f; - - 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. - } - - // The first parameter is a cutoff value on which meshes to - // light. If it's set to small, some meshes will end up 'flashing' - // in and out of light depending on the camera distance from the - // light. - l->setAttenuation(10*radius, cval, lval, qval); - - // base might be null, sometimes lights don't have meshes - if(base) base->attachObject(l); - - return l; -} - -extern "C" void ogre_setAmbient(float r, float g, float b, // Ambient light - float rs, float gs, float bs) // "Sunlight" -{ - g_ambient = ColourValue(r, g, b); - mSceneMgr->setAmbientLight(g_ambient); - - // Create a "sun" that shines light downwards. It doesn't look - // completely right, but leave it for now. - Light *l = mSceneMgr->createLight("Sun"); - l->setDiffuseColour(rs, gs, bs); - l->setType(Light::LT_DIRECTIONAL); - l->setDirection(0,-1,0); -} - -extern "C" void ogre_setFog(float rf, float gf, float bf, // Fog color - float flow, float fhigh) // Fog distance -{ - ColourValue fogColor( rf, gf, bf ); - mSceneMgr->setFog( FOG_LINEAR, fogColor, 0.0, flow, fhigh ); - - // Don't render what you can't see anyway - mCamera->setFarClipDistance(fhigh + 10); - - // Leave this out for now - vp->setBackgroundColour(fogColor); -} - // Copy a scene node and all its children void cloneNode(SceneNode *from, SceneNode *to, char* name) { @@ -185,246 +92,6 @@ extern "C" void ogre_createWater(float level) ent->setCastShadows(false); } -// Manual loader for meshes. Reloading individual meshes is too -// difficult, and not worth the trouble. Later I should make one -// loader for each NIF file, and whenever it is invoked it should -// somehow reload the entire file. How this is to be done when some of -// the meshes might be loaded and in use already, I have no -// idea. Let's just ignore it for now. - -class MeshLoader : public ManualResourceLoader -{ -public: - - void loadResource(Resource *resource) - { - } -} dummyLoader; - -// Load the contents of a mesh -extern "C" void ogre_createMesh( - char* name, // Name of the mesh - int32_t numVerts, // Number of vertices - float* vertices, // Vertex list - float* normals, // Normal list - float* colors, // Vertex colors - float* uvs, // Texture coordinates - int32_t numFaces, // Number of faces*3 - uint16_t* faces, // Faces - float radius, // Bounding sphere - char* material, // Material - // Bounding box - float minX,float minY,float minZ, - float maxX,float maxY,float maxZ, - SceneNode *owner - ) -{ - //std::cerr << "Creating mesh " << name << "\n"; - - MeshPtr msh = MeshManager::getSingleton().createManual(name, "Meshes", - &dummyLoader); - - Entity *e = mSceneMgr->createEntity(name, name); - - owner->attachObject(e); - //msh->setSkeletonName(name); - - // Create vertex data structure - msh->sharedVertexData = new VertexData(); - msh->sharedVertexData->vertexCount = numVerts; - - /// Create declaration (memory format) of vertex data - VertexDeclaration* decl = msh->sharedVertexData->vertexDeclaration; - - int nextBuf = 0; - // 1st buffer - decl->addElement(nextBuf, 0, VET_FLOAT3, VES_POSITION); - - /// Allocate vertex buffer of the requested number of vertices (vertexCount) - /// and bytes per vertex (offset) - HardwareVertexBufferSharedPtr vbuf = - HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_FLOAT3), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); - - /// Upload the vertex data to the card - vbuf->writeData(0, vbuf->getSizeInBytes(), vertices, true); - - /// Set vertex buffer binding so buffer 0 is bound to our vertex buffer - VertexBufferBinding* bind = msh->sharedVertexData->vertexBufferBinding; - bind->setBinding(nextBuf++, vbuf); - - // The lists are read in the same order that they appear in NIF - // files, and likely in memory. Sequential reads might possibly - // avert an occational cache miss. - - // normals - if(normals) - { - //std::cerr << "+ Adding normals\n"; - decl->addElement(nextBuf, 0, VET_FLOAT3, VES_NORMAL); - vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_FLOAT3), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); - - vbuf->writeData(0, vbuf->getSizeInBytes(), normals, true); - - bind->setBinding(nextBuf++, vbuf); - } - - // vertex colors - if(colors) - { - //std::cerr << "+ Adding vertex colors\n"; - // Use render system to convert colour value since colour packing varies - RenderSystem* rs = Root::getSingleton().getRenderSystem(); - RGBA colorsRGB[numVerts]; - RGBA *pColour = colorsRGB; - for(int i=0; iconvertColourValue(ColourValue(colors[0],colors[1],colors[2], colors[3]), - pColour++); - colors += 4; - } - - decl->addElement(nextBuf, 0, VET_COLOUR, VES_DIFFUSE); - /// Allocate vertex buffer of the requested number of vertices (vertexCount) - /// and bytes per vertex (offset) - vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_COLOUR), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); - /// Upload the vertex data to the card - vbuf->writeData(0, vbuf->getSizeInBytes(), colorsRGB, true); - - /// Set vertex buffer binding so buffer 1 is bound to our colour buffer - bind->setBinding(nextBuf++, vbuf); - } - - if(uvs) - { - //std::cerr << "+ Adding texture coordinates\n"; - decl->addElement(nextBuf, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES); - vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_FLOAT2), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); - - vbuf->writeData(0, vbuf->getSizeInBytes(), uvs, true); - - bind->setBinding(nextBuf++, vbuf); - } - - // Create the submesh that holds triangle data - SubMesh* sub = msh->createSubMesh(name); - sub->useSharedVertices = true; - - if(numFaces) - { - //std::cerr << "+ Adding faces\n"; - /// Allocate index buffer of the requested number of faces - HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton(). - createIndexBuffer( - HardwareIndexBuffer::IT_16BIT, - numFaces, - HardwareBuffer::HBU_STATIC_WRITE_ONLY); - - /// Upload the index data to the card - ibuf->writeData(0, ibuf->getSizeInBytes(), faces, true); - - /// Set parameters of the submesh - sub->indexData->indexBuffer = ibuf; - sub->indexData->indexCount = numFaces; - sub->indexData->indexStart = 0; - } - - // Create a material with the given texture, if any. - - // If this mesh has a material, attach it. - if(material) sub->setMaterialName(name); - - /* - // Assign this submesh to the given bone - VertexBoneAssignment v; - v.boneIndex = ((Bone*)bone)->getHandle(); - v.weight = 1.0; - - std::cerr << "+ Assigning bone index " << v.boneIndex << "\n"; - - for(int i=0; i < numVerts; i++) - { - v.vertexIndex = i; - sub->addBoneAssignment(v); - } - */ - /// Set bounding information (for culling) - msh->_setBounds(AxisAlignedBox(minX,minY,minZ,maxX,maxY,maxZ)); - - //std::cerr << "+ Radius: " << radius << "\n"; - msh->_setBoundingSphereRadius(radius); -} - -extern "C" void ogre_createMaterial(char *name, // Name to give - // resource - - float *ambient, // Ambient RBG - // value - float *diffuse, - float *specular, - float *emissive, // Self - // illumination - - float glossiness,// Same as - // shininess? - - float alpha, // Use this in all - // alpha values? - - char* texture, // Texture - - int32_t alphaFlags, - uint8_t alphaTest) // Alpha settings -{ - MaterialPtr material = MaterialManager::getSingleton().create( - name, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - - // This assigns the texture to this material. If the texture - // name is a file name, and this file exists (in a resource - // directory), it will automatically be loaded when needed. If - // not, we should already have inserted a manual loader for the texture. - if(texture) - { - Pass *pass = material->getTechnique(0)->getPass(0); - TextureUnitState *txt = pass->createTextureUnitState(texture); - - // Add transparencly. - - if(alphaFlags != -1) - { - // The 237 alpha flags are by far the most common. Check - // NiAlphaProperty in nif/properties.d if you need to - // decode other values. 237 basically means normal - // transparencly. - if(alphaFlags == 237) - { - // Enable transparency - pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); - - //pass->setDepthCheckEnabled(false); - pass->setDepthWriteEnabled(false); - } - else - std::cout << "UNHANDLED ALPHA FOR " << texture << ": " << alphaFlags << "\n"; - } - } - - // Set bells and whistles - material->setAmbient(ambient[0], ambient[1], ambient[2]); - material->setDiffuse(diffuse[0], diffuse[1], diffuse[2], alpha); - material->setSpecular(specular[0], specular[1], specular[2], alpha); - material->setSelfIllumination(emissive[0], emissive[1], emissive[2]); - material->setShininess(glossiness); -} - extern "C" SceneNode *ogre_getDetachedNode() { SceneNode *node = mwRoot->createChildSceneNode(); @@ -466,54 +133,3 @@ extern "C" SceneNode* ogre_createNode( return node; } - -/* Code currently not in use - -// Insert a raw RGBA image into the texture system. -extern "C" void ogre_insertTexture(char* name, uint32_t width, uint32_t height, void *data) -{ - TexturePtr texture = TextureManager::getSingleton().createManual( - name, // name - "General", // group - TEX_TYPE_2D, // type - width, height, // width & height - 0, // number of mipmaps - PF_BYTE_RGBA, // pixel format - TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - // Get the pixel buffer - HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - - // Lock the pixel buffer and get a pixel box - pixelBuffer->lock(HardwareBuffer::HBL_NORMAL); // for best performance use HBL_DISCARD! - const PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - void *dest = pixelBox.data; - - // Copy the data - memcpy(dest, data, width*height*4); - - // Unlock the pixel buffer - pixelBuffer->unlock(); -} - -// We need this later for animated meshes. -extern "C" void* ogre_setupSkeleton(char* name) -{ - SkeletonPtr skel = SkeletonManager::getSingleton().create( - name, "Closet", true); - - skel->load(); - - // Create all bones at the origin and unrotated. This is necessary - // since our submeshes each have their own model space. We must - // move the bones after creating an entity, then copy this entity. - return (void*)skel->createBone(); -} - -extern "C" void *ogre_insertBone(char* name, void* rootBone, int32_t index) -{ - return (void*) ( ((Bone*)rootBone)->createChild(index) ); -} -*/ diff --git a/old_d_version/ogre/cpp_ogre.cpp b/old_d_version/ogre/cpp_ogre.cpp index 9b38dd458..61385967f 100644 --- a/old_d_version/ogre/cpp_ogre.cpp +++ b/old_d_version/ogre/cpp_ogre.cpp @@ -1,48 +1,5 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.snaptoad.com/ - - This file (cpp_ogre.cpp) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - #include -#include "../util/dbg.h" - -using namespace Ogre; - -ColourValue g_ambient; -int g_lightOn = 0; - -// Set to nonzero if debug mode is enabled -int g_isDebug = 0; - // The global GUI object MyGUI::Gui *mGUI; @@ -51,11 +8,5 @@ MyGUI::Gui *mGUI; // input into MyGUI. int32_t guiMode = 0; -// Include the other parts of the code, and make one big happy object -// file. This is extremely against the grain of C++ "recomended -// practice", but I don't care. #include "../gui/cpp_mygui.cpp" -#include "cpp_framelistener.cpp" -#include "cpp_bsaarchive.cpp" -#include "cpp_interface.cpp" #include "../terrain/cpp_terrain.cpp" diff --git a/old_d_version/ogre/meshloader.d b/old_d_version/ogre/meshloader.d index a6668597b..5065cc87a 100644 --- a/old_d_version/ogre/meshloader.d +++ b/old_d_version/ogre/meshloader.d @@ -389,50 +389,3 @@ struct MeshLoader } } } -/* - // Create a skeleton and get the root bone (index 0) - BonePtr bone = ogre_setupSkeleton(name); - - // Reset the bone index. The next bone to be created has index 1. - boneIndex = 1; - // Create a mesh and assign the skeleton to it - MeshPtr mesh = ogre_setupMesh(name); - - // Loop through the nodes, creating submeshes, materials and - // skeleton bones in the process. - handleNode(node, bone, mesh); - - // Create the "template" entity - EntityPtr entity = ogre_createEntity(name); - - // Loop through once again, this time to set the right - // transformations on the entity's SkeletonInstance. The order of - // children will be the same, allowing us to reference bones using - // their boneIndex. - int lastBone = boneIndex; - boneIndex = 1; - transformBones(node, entity); - if(lastBone != boneIndex) writefln("WARNING: Bone number doesn't match"); - - if(!hasBBox) - ogre_setMeshBoundingBox(mesh, minX, minY, minZ, maxX, maxY, maxZ); - - return entity; -} -void handleNode(Node node, BonePtr root, MeshPtr mesh) -{ - // Insert a new bone for this node - BonePtr bone = ogre_insertBone(node.name, root, boneIndex++); - -} - -void transformBones(Node node, EntityPtr entity) -{ - ogre_transformBone(entity, &node.trafo, boneIndex++); - - NiNode n = cast(NiNode)node; - if(n !is null) - foreach(Node nd; n.children) - transformBones(nd, entity); -} -*/ diff --git a/old_d_version/ogre/ogre.d b/old_d_version/ogre/ogre.d index e75c4ff19..23f89d2e8 100644 --- a/old_d_version/ogre/ogre.d +++ b/old_d_version/ogre/ogre.d @@ -30,19 +30,6 @@ NodePtr placeObject(MeshIndex mesh, Placement *pos, float scale, return node; } -void setAmbient(Color amb, Color sun, Color fog, float density) -{ - ogre_setAmbient(amb.red/255.0, amb.green/255.0, amb.blue/255.0, - sun.red/255.0, sun.green/255.0, sun.blue/255.0); - - // Calculate fog distance - // TODO: Mesh with absolute view distance later - float fhigh = 4500 + 9000*(1-density); - float flow = 200 + 2000*(1-density); - - ogre_setFog(fog.red/255.0, fog.green/255.0, fog.blue/255.0, 200, fhigh); -} - // Gives the placement of an item in the scene (position and // orientation). It must have this exact structure since we also use // it when reading ES files. diff --git a/platform/strings.h b/platform/strings.h index b81af023c..1fb2822a6 100644 --- a/platform/strings.h +++ b/platform/strings.h @@ -2,8 +2,10 @@ #ifndef _STRINGS_WRAPPER_H #define _STRINGS_WRAPPER_H +#ifdef WIN32 #pragma warning(disable: 4996) - #define strcasecmp stricmp +#define snprintf _snprintf +#endif #endif