Banshee Engine Architecture - Introduction

Published November 21, 2014 by Marko Pintera, posted by BearishSun
Do you see issues with this article? Let us know.
Advertisement
This article is imagined as part of a larger series that will explain the architecture and implementation details of Banshee game development toolkit. In this introductory article a very general overview of the architecture is provided, as well as the goals and vision for Banshee. In later articles I will delve into details about various engine systems, providing specific implementation information. The intent of the articles is to teach you how to implement various engine systems, see how they integrate into a larger whole, and give you an insight into game engine architecture. I will be covering various topics, from low level run time type information and serialization systems, multithreaded rendering, general purpose GUI system, input handling, asset processing to editor building and scripting languages. Since Banshee is very new and most likely unfamiliar to the reader I will start with a lengthy introduction.

What is Banshee?

It is a free & modern multi-platform game development toolkit. It aims to provide simple yet powerful environment for creating games and other graphical applications. A wide range of features are available, ranging from a math and utility library, to DirectX 11 and OpenGL render systems all the way to asset processing, fully featured editor and C# scripting. At the time of writing this project is in active development, but its core systems are considered feature complete and a fully working version of the engine is available online. In its current state it can be compared to libraries like SDL or XNA but with a wider scope. Work is progressing on various high level systems as described by the list of features below.

Currently available features

  • Design
    • Built using C++11 and modern design principles
    • Clean layered design
    • Fully documented
    • Modular & plugin based
    • Multiplatform ready
  • Renderer
    • DX9, DX11 and OpenGL 4.3 render systems
    • Multi-threaded rendering
    • Flexible material system
    • Easy to control and set up
    • Shader parsing for HLSL9, HLSL11 and GLSL
  • Asset pipeline
    • Easy to use
    • Asynchronous resource loading
    • Extensible importer system
    • Available importer plugins for:
      • FXB,OBJ, DAE meshes
      • PNG, PSD, BMP, JPG, ... images
      • OTF, TTF fonts
      • HLSL9, HLSL11, GLSL shaders
  • Powerful GUI system
    • Unicode text rendering and input
    • Easy to use layout based system
    • Many common GUI controls
    • Fully skinnable
    • Automatch batching
    • Support for texture atlases
    • Localization
  • Other
    • CPU & GPU profiler
    • Virtual input
    • Advanced RTTI system
    • Automatic object serialization/deserialization
    • Debug drawing
    • Utility library
      • Math, file system, events, thread pool, task scheduler, logging, memory allocators and more

Features coming soon (2015 & 2016)

  • WYSIWYG editor
    • All in one editor
    • Scene, asset and project management
    • Play-in-editor
    • Integration with scripting system
    • Fully customizable for custom workflows
    • One click multi-platform building
  • C# scripting
    • Multiplatform via Mono
    • Full access to .NET library
    • High level engine wrapper
  • High quality renderer
    • Fully deferred
    • Physically based shading
    • Global illumination
    • Gamma correct and HDR rendering
    • High quality post processing effects
  • 3rd party physics, audio, video, network and AI system integration
    • FMOD
    • Physx
    • Ogg Vorbis
    • Ogg Theora
    • Raknet
    • Recast/Detour

Download

You might want to retrieve the project source code to better follow the articles to come - in each article I will reference source code files that you may view for exact implementation details. I will be touching onto features currently available and will update the articles as new features are released. You may download Banshee from its GitHub page: https://github.com/BearishSun/BansheeEngine

Vision

The ultimate goal for Banshee is to be a fully featured toolkit that is easy to use, powerful, well designed and extensible so it may rival AAA engine quality. I'll try to touch upon each of those factors and let you know how exactly it attempts to accomplish that. Ease of use Banshee interface (both code and UI wise) was created to be as simple as possible without sacrificing customizability. Banshee is designed in layers, with the lowest layers providing most general purpose functionality, while higher layers reference lower layers and provide more specialized functionality. Most people will be happy with the simpler more specialized functionality, but lower level functionality is there if they need it and it wasn't designed as an afterthought either. Highest level is imagined as a multi-purpose editor that deals with scene editing, asset import and processing, animation, particles, terrain and similar. Entire editor is designed to be extensible without deep knowledge of the engine - a special scripting interface is provided only for the editor. Each game requires its own custom workflow and set of tools which is reflected in the editor design. On a layer below lies the C# scripting system. C# allows you to write high level functionality of your project more easily and safely. It provides access to the large .NET library and most importantly has extremely fast iteration times so you may test your changes within seconds of making them. All compilation is done in editor and you may jump into the game immediately after it is done - this even applies if you are modifying the editor itself. Power Below the C# scripting layer lie two separate speedy C++ layers that allow you to access the engine core, renderer and rendering APIs directly. Not everyone's performance requirements can be satisfied on the high level and that's why even the low level interfaces had a lot of thought put into them. Banshee is a fully multithreaded engine designed with performance in mind. Renderer thread runs completely separate from the rest of your code giving you maximum CPU resources for best graphical fidelity. Resources are loaded asynchronously therefore avoiding stalls, and internal buffers and systems are designed to avoid CPU-GPU synchronization points. Additionally Banshee comes with built-in CPU and GPU profilers that monitor speed, memory allocations and resource usage for squeezing the most out of your code. Power doesn't only mean speed, but also features. Banshee isn't just a library, but aims to be a fully featured development toolkit. This includes an all-purpose editor, a scripting system, integration with 3rd party physics, audio, video, networking and AI solutions, high fidelity renderer, and with the help of the community hopefully much more. Extensibility A major part of Banshee is the extensible all-purpose editor. Games need custom tools that make development easier and allow your artists and designers to do more. This can range from simple data input for game NPC stats to complex 3D editing tools for your in-game cinematics. The GUI system was designed to make it as easy as possible to design your own input interfaces, and a special scripting interface has been provided that exposes the majority of editor functionality for variety of other uses. Aside from being a big part of the editor, extensibility is also something that is prevalent throughout the lower layers of the engine. Anything not considered core is built as a plugin that inherits a common abstract interface. This means you can build your own plugins for various engine systems without touching the rest of engine. For example, DX9, DX11 and OpenGL render system APIs are all built as plugins and you may switch between them with a single line of code. Quality design A great deal of effort has been spent to design Banshee the right way, with no shortcuts. The entire toolkit, from the low level file system library to GUI system and the editor has been designed and developed from scratch following modern design principles and using modern technologies, solely for the purposes of Banshee. It has been made modular and decoupled as much as possible to allow people to easily replace or update engine systems. Plugin-based architecture keeps all the specialized code outside of the engine core, which makes it easier to tailor it to your own needs by extending it with new plugins. It also makes it easier to learn as you have clearly defined boundaries between systems, which is further supported by the layered architecture that reduces class coupling and makes the direction of dependencies even clearer. Additionally every non trivial method, from lowest to highest layer, is fully documented. From its inception it has been designed to be a multi-platform and a multi-threaded engine. Platform-specific functionality is kept to a minimum and is cleanly encapsulated in order to make porting to other platforms as easy as possible. This is further supported by its render API interface which already supports multiple popular APIs, including OpenGL. Its multithreaded design makes communication between the main and render thread clear and allows you to perform rendering operations from both, depending on developer preference. Resource initialization between the two threads is handled automatically which further allows operations like asynchronous resource loading. Async operation objects provide functionality similar to C++ future/promise and C# async/await concepts. Additionally you are supplied with tools like the task scheduler that allow you to quickly set up parallel operations yourself.

Architecture

Now that you have an idea of what Banshee is trying to acomplish I will describe the general architecture in a bit more detail. Starting with the top level design which is the four primary layers shown on the image below. BansheeLayers.png The layers were created for two reasons:
  • To give developers a chance to pick the level of functionality they need. Some people will want just core and utility and start working on their own engine while others might be just interested in game development and will stick with the editor layer.
  • To decouple code. Lower layers do not know about higher levels and low level code never caters to specialized high level code. This makes the design cleaner and forces a certain direction for dependencies.
Lower levels were designed to be more general purpose than higher levels. They provide very general techniques usually usable in various situations, and they attempt to cater to everyone. On the other hand higher levels provide a lot more focused and specialized techniques. This might mean relying on very specific rendering APIs, platforms or plugins but it also means using newer, fancier and maybe not as widely accepted techniques (e.g. some new rendering algorithm). BansheeUtility This is the lowest layer of the engine. It is a collection of very decoupled and separate systems that are likely to be used throughout all of the higher layers. Essentially a collection of tools that are in no way tied into a larger whole. Most of the functionality isn't even game engine specific, like providing file-system access, file path parsing or events. Other things that belong here are the math library, object serialization and RTTI system, threading primitives and managers, among various others. BansheeCore It is the second lowest layer and the first layer that starts to take shape of an actual engine. This layer provides some very game-specific modules tied into a coherent whole, but it tries to be very generic and offer something that every engine might need instead of focusing on very specialized techniques. Render API wrappers exist here, but actual render APIs are implemented as plugins so you are not constrained by specific subset. Scene manager, renderer, resource management, importers and others all belong here, and all are implemented in an abstract way that they can be implemented/extended by higher layers or plugins. BansheeEngine Second highest layer and first layer with a more focused goal. It is built upon BansheeCore but relies on a specific sub-set of plugins and implements systems like scene manager and renderer in a specific way. For example DirectX 11 and OpenGL render systems are referenced by name, as well as Mono scripting system among others. Renderer that follows a specific set of techniques and algorithms that determines how are all objects rendered also belongs here. BansheeEditor And finally the top layer is the editor. Although it is named as such it also heavily relies on the scripting system and C# interface as those are primarily used through the editor. It is an extensible multi-purpose editor that provides functionality for level editing, compiling script code, editing script objects, playing in editor, importing assets and publishing the game. But also much more as it can be easily extended with your own custom sub-editors. Want a shader node editor? You can build one yourself without touching the complex bits of the engine, you have an entire scripting interface built only for editor extensions. Figure below shows a more detailed structure of each layer as it is designed currently (expect it to change as new features are added). Also note the plugin slots that allow you to extend the engine without actually changing the core. BansheeComplexLayers.png In the future chapters I will explain major systems in each of the layers. These explanations should give you insight on how to use them but also reveal why and how they were implemented. However first off I'd like to focus on a quick guide on how to get started with your first Banshee project in order to give the readers a bit more perspective (And some code!).

Example application

This section is intended to show you how to create a minimal application in Banshee. The example will primarily be using BansheeEngine layer, which is a high level C++ interface. Otherwise inclined users may use the lower level C++ interface and access the rendering API directly, or use the higher level C# scripting interface. We will delve into those interfaces into more detail in later chapters. One important thing to mention is that I will not give instructions on how to set up the Banshee environment and will also omit some less relevant code. This chapter is intended just to give some perspective but the interested reader can head to the project website and check out the example project or the provided tutorial.

Startup

Each Banshee program starts with a call to the Application class. It is the primary entry point into Banshee, handles startup, shutdown and the primary game loop. A minimal application that just creates an empty window looks something like this: RENDER_WINDOW_DESC renderWindowDesc; renderWindowDesc.videoMode = VideoMode(1280, 720); renderWindowDesc.title = "My App"; renderWindowDesc.fullscreen = false; Application::startUp(renderWindowDesc, RenderSystemPlugin::DX11); Application::instance().runMainLoop(); Application::shutDown(); When starting up the application you are required to provide a structure describing the primary render window and a render system plugin to use. When startup completes your render window will show up and then you can run your game code by calling runMainLoop. In this example we haven't set up any game code so your loop will just be running the internal engine systems. When the user is done with the application the main loop returns and shutdown is performed. All objects are cleaned up and plugins unloaded.

Resources

Since our main loop isn't currently doing much we will want to add some game code to perform certain actions. However in order for any of those actions to be visible we need some resources to display on the screen. We will need at least a 3D model and a texture. To get resources into Banshee you can either load a preprocessed resource using the Resources class, or you may import a resource from a third-party format using the Importer class. We'll import a 3D model using an FBX file format, and a texture using the PSD file format. HMesh dragonModel = Importer::instance().import("C:\Dragon.fbx"); HTexture dragonTexture = Importer::instance().import("C:\Dragon.psd");

Game code

Now that we have some resources we can add some game code to display them on the screen. Every bit of game code in Banshee is created in the form of Components. Components are attached to SceneObjects, which can be positioned and oriented around the scene. You will often create your own components but for this example we only need two built-in component types: Camera and Renderable. Camera allows us to set up a viewport into the scene and outputs what it sees into the target surface (our window in this example) and renderable allows us to render a 3D model with a specific material. HSceneObject sceneCameraSO = SceneObject::create("SceneCamera"); HCamera sceneCamera = sceneCameraSO->addComponent(window); sceneCameraSO->setPosition(Vector3(40.0f, 30.0f, 230.0f)); sceneCameraSO->lookAt(Vector3(0, 0, 0)); HSceneObject dragonSO = SceneObject::create("Dragon"); HRenderable renderable = dragonSO->addComponent(); renderable->setMesh(dragonModel); renderable->setMaterial(dragonMaterial); I have skipped material creation as it will be covered in a later chapter but it is enough to say that it involves importing a couple of GPU programs (e.g. shaders), using them to create a material and then attaching the previously loaded texture, among a few other minor things. You can check out the source code and the ExampleProject for a more comprehensive introduction, as I didn't want to turn this article in a tutorial when there already is one.

Conclusion

This concludes the introduction. I hope you enjoyed this article and I'll see you next time when I'll be talking about implementing a run-time type information system in C++ as well as a flexible serialization system that handles everything from saving simple config files, entire resources and even entire level hierarchies.
Cancel Save
0 Likes 13 Comments

Comments

GameCreator

I've been spoiled by engines with simpler code but this looks promising. Good luck with it.

November 21, 2014 11:33 PM
snake5

I generally like the code I saw. It was clean, simple, easy to read. But...

1. Why are you using exceptions to handle errors? That is the most ugly and inefficient method I can imagine. Callback stacks work much better since they preserve the call stack on error. They also use only as much resources as you want them to. Exceptions are generally undefined in terms of performance, often coming with lots of unjustified overhead.

2. Why is there access to code that serves no purpose for the user?


Importer::instance().import<Mesh>("C:\Dragon.fbx");

Why not 'ImportMesh("C:\Dragon.fbx");'? Same goes for all singletons you have there. Unnatural complexity is not helpful.

3. Would be great if you wrote somewhere that this is not a game engine. Just a basic rendering engine with input handling. Didn't see 3D sound playback support, for example. But what about occlusion culling? It's a must-have rendering feature. Skinned meshes? Any kind of culling at all?


So I'm sure it's good for what you say it does. But unfortunately that's far from enough to ship a game.


As for your future plans, some advice: "Play-in-editor" is a bad idea, especially for C++ games. If the game crashes or corrupts memory, it will bring down the whole editor. Not a pretty sight. I suggest implementing playing in a separate process which can be launched by pressing a button in the editor.

November 22, 2014 11:58 AM
BearishSun

Thanks for your input. The whole thing is a work in progress, I hoped I made that clear in the article - many high level features are still upcoming. I agree with you about exceptions but it's not something I have gotten around to replacing yet.

November 22, 2014 12:36 PM
Servant of the Lord

Why are you using exceptions to handle errors? That is the most ugly and inefficient method I can imagine. Callback stacks work much better since they preserve the call stack on error. They also use only as much resources as you want them to.

I've never heard of using callbacks for error handling before. Return results and 'error' pointer/reference parameters, certainly, but never callbacks.

That sounds interesting. Do you know of any articles discussing that method? I can't find anything on google.

November 23, 2014 12:12 AM
snake5

I've never heard of using callbacks for error handling before. Return results and 'error' pointer/reference parameters, certainly, but never callbacks.

That sounds interesting. Do you know of any articles discussing that method? I can't find anything on google.


No idea about articles, I was implementing the approach in my scripting engine. It's kind of like how a debugger works, setting special callbacks that should be called on certain system events. Like the Windows SEH system (SetUnhandledExceptionFilter) or signal handlers in other operating systems.

It's perfect with scripting engines because they free resources automatically in any case, even after skipping code execution. It takes a bit more work to support skipping code execution with usual C++ code, however, the callback still allows you to do introspective debugging and continuing execution after the error/warning. And it blends in nicely with logging systems, allowing the use of error severity codes and error messages. So all kinds of messages can go through the system and their severity can be elevated or reduced via callback overrides.

The typical use case is to simply log all data about the error/warning, perhaps even generate a stack dump file. The other most common one is to ignore a specific error/warning completely because it's expected and the default handling method is sufficient to proceed. Callbacks handle both very well.

And for those few moments when a catch-all handler is necessary near the entry point to continue execution regardless of errors (more common for GUI apps that are not games), there are the regular exceptions.

As for the code, there are two ways, both of which can be hidden in the implementation of a special class.
- method 1:


callbackStack.push( my_new_handler );
<code>
callbackStack.pop();

- method 2:


old_callback = currentCallback;
currentCallback = my_new_handler;
<code>
currentCallback = old_callback;

- with the special class:


CallbackScope cs( my_new_handler );
<code>

The second one requires a bit less resources but you'll have to deal with the old callback manually if you intend to call it from the new one.

November 23, 2014 10:01 AM
JeffCarp

Callbacks for error handling is also popular in web development (i.e.: node.js and Javascript in general).

November 29, 2014 09:17 AM
Cygon

1. Why are you using exceptions to handle errors? That is the most ugly and inefficient method I can imagine. Callback stacks work much better since they preserve the call stack on error. They also use only as much resources as you want them to. Exceptions are generally undefined in terms of performance, often coming with lots of unjustified overhead.

I don't know what turned your opinion against exceptions that much, but they are, I believe not just in my opinion, the cleanest, safest and most readable way of handling errors.

Exceptions preserve the call stack, too. Any connected debugger can be told to break when an exception is thrown, or just when an exception is left unhandled. Getting the callstack when the application crashes at the end user is possible, too.

With exceptions, you also don't have to write tons of boilerplate code pushing and popping cleanup callbacks onto stacks. And you don't have the runtime overhead of a dynamically allocated container (you seem to be using std::vector). Plus you don't have to provide a thread local global "callback stack" to any and all of your engine's systems (creating a monolithic piece of code forcing anyone into this scheme of doing things).

Exceptions are extremely efficient, too. Google "zero cost exception handling" - the days when a try..catch block resulted in a setjmp() instruction are pretty long gone. In fact, you can't create anything remotely as efficient for cleaning up without getting down and dirty with stack frames and the instruction counter.

December 01, 2014 06:41 PM
snake5

I don't know what turned your opinion against exceptions that much

The actual cost and lack of debugging options. Should be obvious.

Exceptions preserve the call stack, too. Any connected debugger...

Do you expect the end user or a collaborating artist to have a debugger and the skill to use it? Seriously?

With exceptions, you also don't have to write tons of boilerplate code pushing and popping cleanup callbacks onto stacks.

What "tons"? I count less than 10 per 10000 lines of code.

And you don't have the runtime overhead of a dynamically allocated container (you seem to be using std::vector).

Implementation details. Use a fixed-size array if you wish, makes no difference to the algorithm. In fact, no need to punch strawmen, whatever "seems to be" isn't a fact.

Plus you don't have to provide a thread local global "callback stack" to any and all of your engine's systems (creating a monolithic piece of code forcing anyone into this scheme of doing things).

Make it fully global, use a mutex. It's obviously not expected to be used more than 10 times per frame anyway (usually closer to 0), probably much less than that, code inside lock would be very fast.

As for "forcing", you're confusing callbacks with exceptions there. When you "throw", you force someone to handle it. With callbacks, it's handled at the same place, without any unexpected jumps and making no difference for the calling code - should it be required to disable the system, it can be done, unlike with a "throw" - it will always jump!

Google "zero cost exception handling"

I did and here's what I've found: http://mortoray.com/2013/09/12/the-true-cost-of-zero-cost-exceptions/ (the punchline starts with "The term “zero-cost exception” is a bit of misnomer")


P.S. C++ exceptions don't need an apologist. They're really not working well for most things, their only value being the leak-preventing call stack jump feature.

December 02, 2014 09:50 AM
Cygon

I don't know if it makes sense to continue this discussion. You seem far too worked up / polarized on this.

  • - Only you need a debugger. The "this application needs to be closed..." window you get when an application crashes (or the terminal output you get on Linux for that matter) contains a crash dump. When you user, artist, whatever sends that to you, you obtain the complete callstack from it. Often the sending process is automated with an error reporting wrapper.

  • - If you only add that code to 10 out of 10000 lines then you have an incomplete callstack. I don't see how that would help with debugging (you first post talks about being able to get a call stack).

  • - If you're using a fixed array you still have overhead. And a limit.

  • - A mutex is the wrong choice: you'd mix callbacks between different threads. If you want to use your stack in a multi-threaded application, you need a thread-local container.

  • - Yes, throw means "I've encountered an error I can't handle in this scope" thus it's jumping to higher scopes until one can deal with the error. And it can't be swiped under the carpet accidentally, letting the application continue in an invalid state.

    And cleanup is still handled locally (see RAII which you demonstrated yourself).

  • - Let me quote two more sentences of that punchline:

    The term “zero-cost exception” is a bit of misnomer: it refers only to the runtime cost when exceptions are not being thrown. The actual overhead in throwing an exception is quite high.

    Zero runtime cost unless an error occurs. Sounds good to me. The article underlines my points, by the way.

You can decide for yourself that you just don't like exceptions, I don't mind. But your arguments here are flawed and strongly opinionated. I think if you manage to take the emotion out of it, you'll find that your concept may have merit for C, but is on very weak footing in C++.

December 02, 2014 11:33 AM
snake5

The "this application needs to be closed..." window you get when an application crashes

I'm talking about every kind of error/suspicious situation (memory access errors, assertions, missing resources) imaginable, not just crashes. So it's a strawman from you again. Obviously if the application crashes I can get a dump out of it. I'm merely proposing an extension of this method to any error imaginable, with all of the included benefits. You can even use exceptions inside a callback. Won't work the other way around.

A side note: having dealt with dumps before, I hate them. I prefer full and verbose call stacks to fragile binary data that would lose all value on any mismatch between compiled binaries.

- If you only add that code to 10 out of 10000 lines then you have an incomplete callstack. I don't see how that would help with debugging (you first post talks about being able to get a call stack).

What do callback stacks have to do with call stacks? Strawman (or a major misunderstanding) again? Call stacks are provided by included debug symbols and a helper library that is able to read them. Completely unrelated to what I'm proposing.

- If you're using a fixed array you still have overhead. And a limit.

What overhead? How is there overhead to setting one pointer and in-/decrementing another, twice for every time you need it? As for a limit, sure there is one. Everything has a limit. But not a hard one and it can be removed, depending on implementation.

- A mutex is the wrong choice: you'd mix callbacks between different threads. If you want to use your stack in a multi-threaded application, you need a thread-local container.

Ah yes, sorry about that, you're right here. Not sure how this is a problem though, I'm sure exceptions have the exact same thing in the implementation, one way or another. Oh, and like I said, the actual stack object is unnecessary. You can keep callbacks in the stack, thus removing these threading issues from your code completely.

- Yes, throw means "I've encountered an error I can't handle in this scope" thus it's jumping to higher scopes until one can deal with the error. And it can't be swiped under the carpet accidentally, letting the application continue in an invalid state.

Sure it can be swiped. `try{ bad_code(); } catch( ... ){}`. Exactly the same thing can be done with callbacks, except that the call stack is not lost and everything moves on from that exact spot.

As for "higher scopes can deal with it", it instantly increases complexity of the code. Suddenly you don't know if a line of code after the throw is supposed to be ever reached. The code becomes unreadable. Sure, you know if you read everything. But does everyone ever have time for everything?

Zero runtime cost unless an error occurs.

Not if...

  • compile target doesn't support it
  • exceptions are expected to happen for each slightly unexpected situation which isn't really an error (file not found, file is found, etc. - examples from boost::filesystem), as is common with exception-happy code, which is when things get really slow

So it's like saying, "use exceptions, love them, but no more than a few in very rare cases". Sounds like a major contradiction to me.

But your arguments here are flawed and strongly opinionated.

Flawed how exactly? I agree about the mutex, that was stupid of me but what have I said that was really wrong here? All I see is nitpicking and strawmen.

I think if you manage to take the emotion out of it, you'll find...

What I have found is coming from experience. Emotions, though sometimes present in my wording, have nothing to do with it. Also, it seems your horse is a bit high. I already know callbacks work, I have been using them for a long long time, haven't stepped aside ever since I designed the implementation for my scripting engine.

December 02, 2014 06:55 PM
Cygon

Yeah, I'm outta this discussion.

You falsely claim I set up a strawman when my point stands, with or without your std::vector, you dishonestly quote a single sentence from a website to make it say the opposite of what it actually did, you call me an "apologist" for just asking what riled you up against exceptions so much. It seems you consider this a war, not a discourse.

This has turned too toxic for me.

-

Regarding the original topic, this looks like an interesting engine, good work!

The general architecture appears to be inspired by Ogre a bit (the RenderSystem, RenderQueue, SceneManager and so on all look very familiar, down to the method names and coding conventions), but I welcome that, since at its core, Ogre is a very nice engine that only accumulated a lot of cruft over the years :)

Maybe you could add a bit more information about the hows and whys of the engine's architecture. It would be pretty interesting and provide something to learn from, apart from just providing a nice introduction into the engine.

December 03, 2014 12:40 PM
snake5

you call me an "apologist" for just asking what riled you up against exceptions so much

Strawman again. I called you an apologist because you defend something that clearly has flaws, without actually proving that anything I mentioned about its flaws was false. You chose instead to attack your incorrect interpretation of an error handling system I proposed, one that has been used in so much software, including operating systems.

with or without your std::vector

No, it's *your* std::vector. That's precisely the problem I'm having here. So-called criticism towards false interpretations. In my second comment here, I clearly mentioned two examples ("Like the Windows SEH system (SetUnhandledExceptionFilter) or signal handlers in other operating systems.") which you clearly haven't bothered to look up, otherwise we wouldn't be having this exchange of words.

---

since at its core, Ogre is a very nice engine that only accumulated a lot of cruft over the years

Ogre has been a horrible engine for a very long time (has it ever been good? doesn't seem like it). I don't know much about the v2.0 rewrite, but the version before that is just horrible. Here, have a look: http://www.bounceapp.com/116414

December 03, 2014 01:39 PM
izackp

This is fantastic, I was aiming for a similar goal for a play in editor, but built on top of Urho3d. I had additional goals of my engine being deterministic with mostly automatic networking (All the user would have to do is choose what variables are 'gameplay variables' and then input/events would be synced between clients). Until I realized C++ is an annoying and redundant language, I wanted a clean modular engine built on the best language possible. At which point, I started looking into Scala and other languages.

Nonetheless, I hope your able to get some steam behind your project. Don't be afraid to reiterate unlike most game engines out there. (Don't be afraid to break things)

I will definitely try out your engine once you have C# support integrated.

December 11, 2014 07:03 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!

Learn about the vision, architecture and design decisions behind Banshee Engine. This is an introductory article that is a part of a larger series.

Advertisement

Other Tutorials by BearishSun

Advertisement