Monday 10 October 2011

Glint 3d: Getting Started Guide


Introduction
In this guide we'll discuss creating your first script, testing it with the Glint 3d Engine (G3E), script compiling and distributing your applications to third-parties. We'll then expand our first example to create a 3d lightmapped model in Blender, export it to file (using our customised exporter) and load it into a G3E 3d world. We'll also see how to create a camera to view the world.

Download the code

Download the code in this article from here. Save yourself time by downloading the code and referring to it as you navigate this tutorial.

Chapter 1 - Hello World

Creating your first script

  • Open your favourite code editor. In this example, we're using Mac's TextEdit.app - a simple editor but it's sufficient for this example, and proves G3E doesn't require a lot of complicated tools to get up and running.
  • Read the Lua reference manual to learn more about the G3E programming language.
  • Add the following to your script:

    -- Create a local variable to hold our message string.
    local testString = 'Hello World from G3E';
    
    -- Function to display a message box
    -- title: The message box title
    -- message: The string displayed in the message box
    local function createTestMessageBox(title, message)
      -- The glint interface is static and created during startup.
      -- Use the dot-notation to access it's functions.
      -- The glint interface also defines a lot of constants (eg. glint.OS_MESSAGE_STYLE_OK).
      -- Any function parameters not explicitly defined are set to nil
      glint.showMessageBox(message, title, glint.OS_MESSAGE_STYLE_OK);
    end
    
    
    -- Any code not within a function is automatically executed by G3E when the script is loaded into the engine.
    -- This is where our application starts.
    -- Call our function, pass in some parameters.
    createTestMessageBox('Test App', testString);

    • Save the script - call it hello_world.lua.


        Running your first script

        • Run the G3E application (in Mac, it's called glint3d.app - in Windows, it's called glint3d.exe).
        • Without command-line arguments, G3E displays an Open File dialog to select a script.
        • Select the hello_world.lua script. G3E loads the script and executes all code outside of any functions.
        • A 'hello world' message box is displayed. Success!

        Running scripts - Advanced options

        Running your scripts by starting the G3E app and navigating with the Open File dialog is an easy way to test scripts, but here are more advanced options:
        • Option (1) Open the command-prompt.
        1. On Windows: Type 'glint3d.exe [pathname/]scriptfilename [script_arguments]'.
        2. On Mac: Type 'open glint3d.app --args [pathname/]scriptfilename [script_arguments]'.
        • Option (2) Create a shortcut.
        1. On Windows: Edit the shortcut properties to run 'glint.exe [pathname/]scriptfilename [script_arguments]'.
        2. On Mac: Use the AppleScript Editor and enter the following command 'do shell script "open -a glint3d.app --args [pathname/]scriptfilename [script_arguments]"'.
        • Option (3) Create a file association.
        1. See the File Associations section for more info.
        • Option (4) Rename the startup script to main.lua and place in the G3E working folder.
        1. On Windows: Move main.lua to the glint3d.exe folder. Start the glint3d.exe. It will automatically run the main.lua script without displaying an Open File dialog.
        2. On Mac: Move main.lua to the glint3d.app 'Resources' folder (you first have to open the glint3d.app bundle to view the contents). Start the glint3d.app. It will automatically run the main.lua script without displaying an Open File dialog.
        Compiling scripts
        The thank-you gift pack includes the LuaC.exe script compiler. It compiles your text-based lua scripts into byte-code. They are no longer human-readable which helps to keep your IP private. Compiled scripts can also decrease loading times so it's certainly worth compiling your scripts before distributing your app to third-parties.
        Compile the hello_world.lua script using these steps:
        • Open the command-prompt.
        • Change to the G3E developer tools folder (where the LuaC executable resides)
        • Run the script compiler without any arguments to read more about the compiler options.
          1. On Windows: Type "luac.exe".
          2. On Mac: Type "luac".
        • Run the script compiler, passing the hello_world.lua script as an application argument. Call the output filehello_world.luc:

          1. On Windows: Type "luac.exe -o hello_world.luc [pathname/]hello_world.lua".
          2. On Mac: Type "luac -o hello_world.luc [pathname/]hello_world.lua".

        Test the compiled script by running it with G3E as you previously did with the text-based lua script. The output should be the same.

          Distributing your apps

          When distributing your apps to third-parties you must also include the G3E executable and associated files. Our simple licensing allows you to redistribute the G3E royalty-free.
          • Compile your application scripts.
          • Copy the G3E executable into an output folder.
          • Copy your app's scripts and resources to the output folder:
            1. On Windows: Copy the scripts and resources to the same location as the G3E executable (glint3d.exe). Use subfolders as required but leave the startup script in the base folder. Rename the startup script to main.lua.
            2. On Mac: Copy the scripts and resources to the Resources folder inside the G3E bundle (glint3d.app). Use subfolders as required but leave the startup script in the base folder. Rename the startup script to main.lua.





          Chapter 2 - Creating G3E resources

          Programmer's Reference

          Open the Glint 3d programming reference via the glint3d-help.capricorn76.com site.
          • It contains a comprehensive description of the G3E interfaces and functions.
          • Use it to help you with your G3E programming experience.

          Tests & Examples

          There are over 4000 lines of code testing the Glint 3d features.
          • Open the G3E test folder.
          • Unzip the G3E tests
          • Open the test.lua script and examine the code.
          • Run the test.lua script using the G3E executable.
          • Edit the test.lua to and re-run to experiment with G3E.

          File associations

          You can associate any file extension with the G3E executable to simplify application startup.
          • File associations will start the G3E app by double-clicking an associated script file. The script filename is passed to the G3E app during startup. This is similar to passing the script filename as an argument via the command line.
          • Each OS provides it's a way of setting up file associations using the Open With command from their File Explorers.
          • Alternatively, we've included a createFileAssociations.bat (for Windows) with the thank-you gift-pack. Edit the .bat file to specify the file extensions and the location of the G3E executable. By default, it associates *.lua with the Glint 3d executable.
          • When distributing the G3E executable with your applications, create the desired file associations in your installation process.

          Code editors

          Use your favourite code editor to edit lua scripts used with the Glint 3d Engine.
          • We use and recommend SciTE, Eclipse and Unitron.
          • You can even use a basic text-editor installed with your OS.

          Developer tools

          G3E licensees receive a thank-you gift-pack including a Blender 3d exporter, gui-editor, script-compiler, and extra dynamic modules to extend the Glint 3d Engine functionality. Purchase a Glint 3d license to receive your developer thank-you gift-pack.

          Creating 3d worlds

          Use your favourite 3d world editor (we recommend Blender 3d) to create your world's static geometry.
          • Export the model using our Blender Irrlicht exporter (see the thank-you gift-pack). It exports all the Irrlicht model parameters including materials, texture coordinates, and custom shader names. It also handles multi-texture models (for light-mapping and advanced shaders). This exporter creates Irrlicht scenes (.irr), meshes (.irrmesh) and can also export camera, dynamic lights.
          • If you don't use our custom exporter, you can export the static geometry to any of the compatible G3E model formats, including Irrlicht mesh (.irrmesh), 3D Studio (.3ds), Blitz Basic (.b3d), Cartography shop 4 (.csm), Collada (.dae, .xml), Delgine DeleD (.dmf), DirectX (.x), Maya (.obj), Milkshape (.ms3d), My3D (.my3d), OCT (.oct), OGRE Meshes (.mesh), Pulsar LMTools (.lmts), Quake 3 levels (.bsp), Quake 2 models (.md2)
          • In G3E, create a 3d world unit (G3E units are used for static geometry & can be displayed using octrees). Supply the 3d-model's filename to the entity during initialisation. See the CWorldManager.createUnit() function.
          • Use the CWorldUnit functions to control the unit's properties.

          Creating 3d animations

          Use your favourite 3d world editor (we recommend Blender 3d) to create an animated model with skeletal animations.
          • Export the animated model to DirectX (.x) or Blitz3d (.b3d) file formats.
          • In G3E, create a 3d world agent (only G3E agent-entities use animations) and supply the 3d-model's filename to the entity during initialisation. See the CWorldManager.createAgent() function.
          • Use the CWorldAgent functions like setAnimationLooping() etc to control the agent's animations.
          • We use and recommend the Blender 3d editor with the DirectX-exporter and b3d-exporter for 3D skeletal animations.
          • G3E supports the DirectX (.x), Blitz3d (.b3d), MD2/MD3 (.md2, .md3) file formats.

          Creating textures

          Use your favourite paint program or download 2D textures from the internet.
          • Textures dimensions should always be a factor of 2 pixels wide/high (eg 256x256, 128x512 etc) unless the graphics driver supports other dimensions. You can check what features are supported by the graphics driver using theCGraphicsManager.queryFeature() function.
          • We use and recommend the Gimp editor or Photoshop.
          • G3E supports the Bitmap (.bmp), Jpeg (.jpg), Targa (.tga), Zsoft Paintbrush (.pcx), Portable Network Graphics (.png), Adobe Photoshop (.psd) file formats.

          Creating sound effects

          Use your favourite sound editor or download free sounds from the internet.
          • For 2d sounds (eg. background music), save the sound in stereo format.
          • For 3d sounds (eg. sfx in your 3d worlds), save the sound in mono format.
          • G3E supports the Ogg-vorbis (.ogg), Riff-wave (.wav) file formats.


          Chapter 3 - Creating a 3d world

          Initialising the G3E engine components

          The G3E must first be initialised to use 2d/3d graphics, physics or sound. Each engine component may be initialised with it's own parameters, or not at all. Only initialised engine components may be used from within your scripts. In this example, we'll initialise the graphics component.
          • Open your code editor.
          • Create a function called startupG3E() to initialise the engine.

          local function startupG3E()
            local engine = glint.construct();
            local factory = engine:getFactory();
          
            -- Initialise the engine.
            -- This can alternatively be done in a single step by passing the init() params to the contruct() function above.
            engine:init{  graphics  =  {  driver=glint.GRAPHICS_OPENGL,
                              screenWidth=800,
                              screenHeight=600,
                              frameRate=30,
                            },
                    -- If the engine fails to be created, an error will be raised because silentErrors=false
                    -- To gracefully handle any errors during initialisation, set silentErrors=true & check that the engine initialised successfully
                    silentErrors=false
                    };
          
            -- Get the graphics engine interface from the G3E instance
            local graphics = engine:getGraphicsManager();
          
            -- Perform a few tests on the engine
            print('Graphics initialised', graphics:isInitialised());
            print('Graphics driver type', graphics:getDriverType() == glint.GRAPHICS_OPENGL);
            print('Graphics width', graphics:getScreenWidth() == 800);
            print('Graphics height', graphics:getScreenHeight() == 600);
            
            -- Return the new G3E instance
            return engine;
          end
          
          -- Program starts here
          local engine = startupG3E();
          
          -- If the engine was intialised, then show message and shutdown
          if (engine) then
            -- Show message indicating that engine initialised
            glint.showMessageBox('G3E instance created', 'Hello world v2', glint.OS_MESSAGE_STYLE_OK);
            engine:shutdown();
          end

          • The startupG3E() function creates a new G3E instance passing the initialisation parameters and returns it on success.
          • We check that the engine is created - displaying a message to the user.
          • At this point, we simply shut down the engine.
          • Note that all created G3E objects use the colon-notation ':' to access functions and the dot-notation '.' to access properties. This is typical of OO objects in lua. Static functions (like the glint interface) use the dot-notation to access functions because they don't maintain state (data).

          Loading a 3d world

          Creating your 3d worlds can be achieved in 2 ways.
          1. Model an entire G3E scene with multiple entities, light-mapping, materials, advanced shaders, dynamic lights and cameras; export it using our Blender exporter, and load the entire scene into G3E using the CWorldManager.load()function.
          2. Model individual entities in a 3d modeller; export them to a compatible G3E format (eg. .x, .3ds, .dae, .irrmesh etc), and then refer to them when creating G3E world units/agents.
          In this example, we use the second method because the Blender exporter is available only to G3E licensees.

          Creating a 3d entity in script

          Once the G3E engine has been initialised, we populate it with world entities including dynamic lights, cameras, units (for static geometry) & agents (for animated geometry - typically players & NPCs). First thing is we need resources - 3d models with textures used to represent the G3E world units & agents.
          • Create (using your favourite 3d modeller) or download a 3d model in a compatible G3E format. In this example, we've included a simple cube called cube.x.
          • Open your code editor.
          • Create a function called create3dScene() to initialise the 3d world. Create a textured cube, and a camera to view it.
          • The run the G3E for a fixed time to view the world.


          -- Create a 3d world in the G3E 
          local function create3dScene(engine)
            local world = engine:getWorldManager();
            local factory = engine:getFactory();
            local cam1 = world:createCamera  {  id='cam1',
                      position=factory:vector3d(0, 2, -5),
                      upVector=factory:vector3d(0, 1, 0)
                      };
                              
            local cube = world:createUnit  {  id='cube',
                      position=factory:vector3d(0, 0, 0),
                      scale=factory:vector3d(2, 1, 1),
                      rotation=factory:vector3d(0, 45, 0),
                      texture0='crate.jpg'
                      };
                            
            -- Run the engine for 3 seconds so that we can see the world
            engine:run(3000);
            glint.showMessageBox('G3E scene created', 'Hello world v2', glint.OS_MESSAGE_STYLE_OK);
          end


          Running the engine

          The previous section touched on running the G3E for a fixed time with the CAppEngine.run(fixed_time) function. But typically we want to run the engine until the user does something (eg. press Esc, hit a menu button etc.). This is achieved by doing two things:
          1. Subscribe to a G3E event (using CEventsManager), usually a user-input related event like GUI-input, key-input.
          2. Run the G3E (using CAppEngine.run()) until it's stopped from a subscriber callback.

          Creating an event subscriber to handle user input

          In this example, we'll create a key-input subscriber to handle the user's key presses. We'll define a callback function that G3E invokes when the event occurs.
          • Open your code editor.
          • Add the following subscriber callback function:


          -- Key subscriber callback function
          local function keySubscriberCallback(params)
            -- keyState=true means key down, keyState=false means key up
            if (not(params.keyState) and (params.keyCode == glint.KEY_ESCAPE)) then
              -- Stop the engine. This forces a previous engine:run() call to complete
              engine:stop();
            end
          end

            Before running the G3E, create a key subscriber passing the keySubscriberCallback() function as a parameter:

            -- Create a key subscriber, pass the callback function
            local events = engine:getEventsManager();
            local keySubscriber = events:subscribeKey{callback=keySubscriberCallback};

          • Run the G3E until it's stopped from within the subscriber callback:


          	engine:run();


            • Once the user presses ESCAPE, the engine:stop() is called terminating the engine:run() processing loop.
            • Commence the cleanup process to release all resources.

            Cleaning up the engine and terminating the app

            It's important to release all G3E resources when appropriate and to release subscribes to prevent unexpected function callbacks.
            • In the code editor, unsubscribe to the key-events after the engine:run() has completed:


            	keySubscriber:unsubscribe();


            • Shutdown the G3E, releasing all resources.


            	engine:shutdown();


            Conclusion

            That completes this guide to getting started with the Glint 3d Engine.