Browse Source

Load meshes and create nodes separately

Macoy Madson 2 months ago
8 changed files with 148 additions and 26 deletions
  1. +3
  2. +16
  3. +1
  4. +9
  5. +112
  6. +3
  7. +4
  8. BIN

+ 3
- 1
.gitignore View File

@ -39,4 +39,6 @@ bin/

+ 16
- 0

@ -0,0 +1,16 @@
Copyright (c) 2020 Macoy Madson
This file is part of Gamelib.
Gamelib is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gamelib is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Gamelib. If not, see <>.

+ 1
- 1

@ -1 +1 @@
Subproject commit 5ce4976faec4de4d562a9621b4e69f6dc2225d04
Subproject commit 588e39756baff2f81d57ed760cd057eafd063fce

+ 9
- 0 View File

@ -18,3 +18,12 @@ Build:
* Asset pipeline
This is a work in progress.
For me:
cd ~/Development/code/repositories/gamelib/Dependencies/ogre-next/build/Debug/bin
./OgreMeshTool_d -e -O puqs ~/Development/code/repositories/gamelib/test/data/Models/Suzanne.mesh.xml

+ 112
- 19
src/OgreCore.cake View File

@ -1,3 +1,5 @@
(set-cakelisp-option cakelisp-src-dir "Dependencies/cakelisp/src")
(c-import "<stdio.h>"
;; Ogre dependencies
@ -11,25 +13,48 @@
;; Not ported over to Cakelisp yet
;; TODO: convert these functions to cakelisp eventually
(defun ogre-initialize (&return bool)
(return (OgreInitialize)))
(defun ogre-shutdown ()
(defun ogre-load-mesh (name (* (const char)))
(var sceneManager (* (in Ogre SceneManager)) (ogreGetSceneManager))
;; If false is returned, you should break from the main loop (the window has been closed)
(defun ogre-handle-window-events (&return bool)
(call (in Ogre WindowEventUtilities messagePump))
(return (not g_ogreWindowShouldQuit)))
;; If false is returned, you should break from the main loop (an error has occurred)
(defun ogre-render-frame (&return bool)
(return (on-call-ptr g_ogreRoot renderOneFrame)))
;; I'd be happy if this goes away in the "real" language, but it seems necessary for C++ interop
(namespace Ogre
(class Item)
(class SceneNode)))
;; The client of this API should not need access the internals of this structure
(defstruct mesh-handle
mesh-item (* (in Ogre Item)))
(defstruct scene-node
node (* (in Ogre SceneNode)))
(defun ogre-load-mesh (name (* (const char)) &return mesh-handle)
(var scene-manager (* (in Ogre SceneManager)) (ogreGetSceneManager))
;; Load the v1 mesh. Notice the v1 namespace
;; Also notice the HBU_STATIC flag; since the HBU_WRITE_ONLY
;; bit would prohibit us from reading the data for importing.
(var v1Mesh Ogre::v1::MeshPtr
(var mesh-v1 Ogre::v1::MeshPtr
(on-call (call (in Ogre v1 MeshManager getSingleton)) load
name Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME
Ogre::v1::HardwareBuffer::HBU_STATIC Ogre::v1::HardwareBuffer::HBU_STATIC))
(var halfPosition bool true)
(var halfUVs bool true)
(var useQtangents bool true)
(var half-position bool true)
(var half-UVs bool true)
(var use-Q-tangents bool true)
;; Create a v2 mesh to import to, with a different name (arbitrary).
(var mesh-name-v2 (const Ogre::String) (+ name (Ogre::String " Imported")))
@ -37,26 +62,94 @@
(var v2Mesh Ogre::MeshPtr
(on-call (call (in Ogre MeshManager getSingleton)) createByImportingV1
mesh-name-v2 Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME
(on-call v1Mesh get)
halfPosition halfUVs useQtangents))
(on-call mesh-v1 get)
half-position half-UVs use-Q-tangents))
;; We don't need the v1 mesh. Free CPU memory, get it out of the GPU.
;; Leave it loaded if you want to use athene with v1 Entity.
(on-call-ptr v1Mesh unload)
(on-call-ptr mesh-v1 unload)
;; Create an Item with the model we just imported.
;; Notice we use the name of the imported model. We could also use the overload
;; with the mesh pointer:
;; item = sceneManager->createItem( v2Mesh, Ogre::SCENE_DYNAMIC );
(var item (* Ogre::Item) (on-call-ptr sceneManager createItem
;; item = scene-manager->createItem( v2Mesh, Ogre::SCENE_DYNAMIC );
(var item (* Ogre::Item) (on-call-ptr scene-manager createItem
mesh-name-v2 Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME
;; If false is returned, you should break from the main loop (the window has been closed)
(defun ogre-handle-window-events (&return bool)
(call (in Ogre WindowEventUtilities messagePump))
(return (not g_ogreWindowShouldQuit)))
(var mesh-handle mesh-handle (array item))
(return mesh-handle))
;; If false is returned, you should break from the main loop
(defun ogre-render-frame (&return bool)
(return (on-call-ptr g_ogreRoot renderOneFrame)))
(defun ogre-node-from-item (mesh-handle mesh-handle &return scene-node)
(var new-scene-node scene-node (array nullptr))
(var scene-manager (* (in Ogre SceneManager)) (ogreGetSceneManager))
(var root-scene-node (* Ogre::SceneNode) (on-call-ptr scene-manager getRootSceneNode))
(when root-scene-node
;; WTF - this should work, but it's almost like the root scene node's vtable is wrong
;; Ogre::SceneNode* sceneNode = root-scene-node->createChildSceneNode(Ogre::SCENE_DYNAMIC);
(var scene-node (* Ogre::SceneNode)
(type-cast (on-call-ptr root-scene-node createChild) (* Ogre::SceneNode)))
(when scene-node
(on-call-ptr scene-node attachObject (field mesh-handle mesh-item))
(set (field new-scene-node node) scene-node)))
(return new-scene-node))
;; Creates forward declarations in header files.
;; Example usage:
;; (forward-declare (namespace Ogre (class item) (struct my-struct)))
;; Outputs namespace Ogre { class item; struct my-struct;}
(defgenerator forward-declare ()
;; TODO: Support global vs local?
(var is-global bool true)
(var output-dest (& (<> std::vector StringOutput))
(? is-global output.header output.source))
(var end-invocation-index int (FindCloseParenTokenIndex tokens startTokenIndex))
(var start-body-index int (+ 2 startTokenIndex))
(var current-index int start-body-index)
(var namespace-stack (<> std::vector int))
(while (< current-index end-invocation-index)
(var current-token (& (const Token)) (at current-index tokens))
;; Invocations
(when (= TokenType_OpenParen (field current-token type))
(var invocation-token (& (const Token)) (at (+ 1 current-index) tokens))
((= 0 (on-call (field invocation-token contents) compare "namespace"))
(unless (< (+ 3 current-index) end-invocation-index)
(ErrorAtToken invocation-token "missing name or body arguments")
(return false))
(var namespace-name-token (& (const Token)) (at (+ 2 current-index) tokens))
(addStringOutput output-dest "namespace"
StringOutMod_SpaceAfter (addr invocation-token))
(addStringOutput output-dest (field namespace-name-token contents)
StringOutMod_None (addr namespace-name-token))
(addLangTokenOutput output-dest StringOutMod_OpenBlock (addr namespace-name-token))
(on-call namespace-stack push_back (FindCloseParenTokenIndex tokens current-index)))
((or (= 0 (on-call (field invocation-token contents) compare "class"))
(= 0 (on-call (field invocation-token contents) compare "struct")))
(unless (< (+ 2 current-index) end-invocation-index)
(ErrorAtToken invocation-token "missing name argument")
(return false))
(var type-name-token (& (const Token)) (at (+ 2 current-index) tokens))
(unless (ExpectTokenType "forward-declare" type-name-token TokenType_Symbol)
(return false))
(addStringOutput output-dest (field invocation-token contents)
StringOutMod_SpaceAfter (addr invocation-token))
(addStringOutput output-dest (field type-name-token contents)
StringOutMod_None (addr type-name-token))
(addLangTokenOutput output-dest StringOutMod_EndStatement (addr type-name-token)))
(ErrorAtToken invocation-token "unknown forward-declare type")
(return false))))
(when (= TokenType_CloseParen (field current-token type))
(for-in close-block-index int namespace-stack
(when (= close-block-index current-index)
(addLangTokenOutput output-dest StringOutMod_CloseBlock
(addr (at current-index tokens))))))
;; TODO: Support function calls so we can do this recursively
;; (set current-index
;; (getNextArgument tokens current-index end-invocation-index))
(incr current-index))
(return true))

+ 3
- 3
src/OgreInitialize.cpp View File

@ -230,12 +230,12 @@ bool OgreInitialize()
compositorManager->addWorkspace(g_sceneManager, g_window->getTexture(), camera, workspaceName,
Ogre::ResourceGroupManager::getSingleton().addResourceLocation("data/Models", "FileSystem",
// Mesh importing
if (false)
Ogre::ResourceGroupManager::getSingleton().addResourceLocation("data/Models", "FileSystem",
Ogre::v1::MeshPtr v1Mesh;
Ogre::MeshPtr v2Mesh;
// Load the v1 mesh. Notice the v1 namespace

+ 4
- 2
test/OgreApp.cake View File

@ -1,4 +1,5 @@
;; TODO: Cakelisp include paths
(set-cakelisp-option cakelisp-src-dir "Dependencies/cakelisp/src")
(import "../src/OgreCore.cake")
(c-import "<stdio.h>")
@ -7,7 +8,8 @@
;; Ogre uses exceptions for error handling, so we can't gracefully close without getting all that
;; stuff set up (which I don't really want to do; it belongs in Gamelib)
;; (ogre-load-mesh "Test.mesh")
(var monkey-mesh mesh-handle (ogre-load-mesh "Suzanne.mesh"))
(var monkey-node scene-node (ogre-node-from-item monkey-mesh))
(var exit-reason (* (const char)) nullptr)

test/assets/Monkey.blend View File