luascene.cpp

Download
#include "ExampleApplication.h"
#include <stdexcept>
#include <lua.hpp>

using std::runtime_error;
// ExampleApplication.h has done a "using namespace ogre"

// This class simply gives us a torch attached to our camera.
class MyExampleFrameListener : public ExampleFrameListener
{
protected:
    SceneNode *mCameraNode;

public:
    MyExampleFrameListener( RenderWindow* win, Camera* cam, SceneNode *camnode ) : ExampleFrameListener( win, cam )
    {
        mCameraNode = camnode;
    }
    // Overidden to move scene node rather than the camera itself.
    void moveCamera()
    {
        // Make all the changes to the camera
        // Note that YAW direction is around a fixed axis (freelook style) rather than a natural YAW
        //(e.g. airplane)
        mCameraNode->yaw(mRotX, Node::TS_WORLD);
        mCameraNode->pitch(mRotY);
        mCameraNode->translate(mTranslateVector, Node::TS_LOCAL);
    }
};

// Lua bound functions must be static, however to call methods on the application object you need
// a pointer or reference to it.  Options to this would be a singleton, or passing a
// pointer to Lua code which then can be passed back.  Here I do a very simple version of a
// singleton.
// Despite being static, it does not stop us making the bound functions methods of the application
// and able to access the protected member "g_application" (which is also static).
// Static methods, can only access static members, unless you have a pointer to an object, a replacement
// for "this" basically.   This is exactly what g_application is.

class LuaSceneApp : public ExampleApplication
{
protected:
    lua_State *L;
    SceneNode *mCameraNode;
    static LuaSceneApp *g_application;

public:

    static int CreateSceneObject( lua_State * );

    LuaSceneApp();

    ~LuaSceneApp()
    {
        lua_close( L );
    }
protected:

    void createScene(void)
    {
        mSceneMgr->setAmbientLight( ColourValue( .1, .1, .1 ) );
        loadScene( "/home/nigel/Blender/meshes.lua" );

        Light* pLight = mSceneMgr->createLight("CameraLight");
        pLight->setPosition(0.0f, 0.0f, 0.0f);
        pLight->setDiffuseColour( ColourValue( 0.6f, 0.6f, 0.6f ) );
        mCameraNode->createChildSceneNode( "CameraLightNode" )->attachObject( pLight );
    }

    void createCamera()
    {
        // Create the camera
        mCamera = mSceneMgr->createCamera("PlayerCam");
        mCameraNode = mSceneMgr->getRootSceneNode()->createChildSceneNode( "CameraNode" );
        mCameraNode->attachObject( mCamera );
        mCameraNode->setPosition(Vector3(0,0,200));

        // Look back along -Z
        mCamera->lookAt(Vector3(0,0,100));
        mCamera->setNearClipDistance(1);
    }

    void createFrameListener(void)
    {
        mFrameListener= new MyExampleFrameListener(mWindow, mCamera, mCameraNode);
        mFrameListener->showDebugOverlay(true);
        mRoot->addFrameListener(mFrameListener);
    }

    void runScript( const char *filename )
    {
        if(luaL_loadfile( L, filename ) || lua_pcall( L, 0, 0, 0 ))
        {
            const char *errorstr = lua_tostring( L, -1 );
            lua_pop( L, 1 ); // The lua GC will not be run before the
                             // exception constructor, so the string
                             // will still be there.
            throw runtime_error( errorstr );
        }

        return;
    }

    void runScriptStr( const char *source )
    {
        if(luaL_loadstring( L, source ) || lua_pcall( L, 0, 0, 0 ))
        {
            const char *errorstr = lua_tostring( L, -1 );
            lua_pop( L, 1 ); // The lua GC will not be run before the
                             // exception constructor, so the string
                             // will still be there.
            throw runtime_error( errorstr );
        }

        return;
    }

    void loadScene( const char *filename )
    {
        runScript( filename );

        const char *loader = "print 'Loading scene...'\n";

        runScriptStr( loader );

        runScript( "loader.lua" );
    }
};

// List of functions we are exposing to Lua
static const luaL_Reg luaAPI[] =
{
    { "CreateSceneObject", LuaSceneApp::CreateSceneObject },
    { NULL, NULL },
};

LuaSceneApp* LuaSceneApp::g_application = NULL;

// Here in the application start up, we crank up Lua, and register
// any functions we want bound.  Opening the Lua libraries is not
// strictly necessary.  Do you trust where the Lua scriptes came from?
LuaSceneApp::LuaSceneApp()
{
    assert( !g_application );

    g_application = this;

    L = lua_open();
    luaL_register( L, "Ogre", luaAPI );
    luaL_openlibs( L );
}

Vector3 lua_toVector3( lua_State *L, int index )
{
    // table at 'index' with 3 numbers, at index'es 1,2,and 3, are x,y and zed

    Vector3 vec;

    lua_pushnumber( L, 1 );
    lua_gettable( L, index );
    vec.x = lua_tonumber( L, -1 );
    lua_pop( L, 1 );

    lua_pushnumber( L, 2 );
    lua_gettable( L, index );
    vec.y = lua_tonumber( L, -1 );
    lua_pop( L, 1 );

    lua_pushnumber( L, 3 );
    lua_gettable( L, index );
    vec.z = lua_tonumber( L, -1 );
    lua_pop( L, 1 );

    return vec;
}

Quaternion lua_toQuaternion( lua_State *L, int index )
{
    // table at 'index' with 4 numbers, at index'es 1, 2, 3 and 4,
    // are w, x, y and zed
    float w, x, y, z;

    lua_pushnumber( L, 1 );
    lua_gettable( L, index );
    w = lua_tonumber( L, -1 );
    lua_pop( L, 1 );

    lua_pushnumber( L, 2 );
    lua_gettable( L, index );
    x = lua_tonumber( L, -1 );
    lua_pop( L, 1 );

    lua_pushnumber( L, 3 );
    lua_gettable( L, index );
    y = lua_tonumber( L, -1 );
    lua_pop( L, 1 );

    lua_pushnumber( L, 4 );
    lua_gettable( L, index );
    z = lua_tonumber( L, -1 );
    lua_pop( L, 1 );

    return Quaternion( w, x, y, z );
}

int LuaSceneApp::CreateSceneObject( lua_State *L )
{
    assert( g_application );

    // Params, name, filename, location, rotation
    // location and scale are tables with 3  numbers.
    // Rotation is the same but with 4.

    const char *name;
    const char *filename;

    name = luaL_checkstring( L, 1 );
    filename = luaL_checkstring( L, 2 );

    LogManager::getSingleton().stream() << name << " " << filename;

    luaL_checktype( L, 3, LUA_TTABLE );
    Vector3 location = lua_toVector3( L, 3);

    luaL_checktype( L, 4, LUA_TTABLE );
    Quaternion rotation = lua_toQuaternion( L, 4);

    luaL_checktype( L, 5, LUA_TTABLE );
    Vector3 scale = lua_toVector3( L, 5);

    LogManager::getSingleton().stream() << "Loc: " << location << " Rot: " << rotation << " Scale: " << scale;

    Entity *entity = g_application->mSceneMgr->createEntity( name, filename );
    SceneNode *node = g_application->mSceneMgr->getRootSceneNode()->createChildSceneNode( name );
    node->attachObject( entity );
    node->setPosition( location );
    node->setOrientation( rotation );

    node->setScale( scale );

    lua_pop( L, 4 );

    return 0;
}

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
    LuaSceneApp app;

    try
    {
        app.go();
    }
    catch( std::exception& e ) // This catches "Ogre::Exception" too.
    {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
        MessageBox( NULL, e.what(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
        fprintf(stderr, "An exception has occurred: %s\n",
            e.what());
#endif
    }

    return 0;
}

Back to Top