I'm a huge fan of having a game engine that has the abilty to adapt, not just in what it can do, but also in how it can handle new code. Recently, for my graphics subsystem, I wrote a class to be overriden that works like this:
class LowLevelGraphicsInterface {
virtual bool setRenderTarget(const RenderTarget* renderTarget) = 0;
virtual bool setStreamSource(const VertexBuffer* vertexBuffer) = 0;
virtual bool setShader(const Shader* shader) = 0;
virtual bool draw(void) = 0;
//etc.
};
My idea was to create a list of functions that are universal among most graphics APIs. Then for DirectX11 I would just create a new child class:
class LGI_DX11 : public LowLevelGraphicsInterface {
virtual bool setRenderTarget(const RenderTarget* renderTarget);
virtual bool setStreamSource(const VertexBuffer* vertexBuffer);
virtual bool setShader(const Shader* shader);
virtual bool draw(void);
//etc.
};
Each of these functions would then interface with DX11 directly. I do realize that there is a layer of indirection here. Are people turned off by this fact?
Is this a widely used method? Is there something else I could/should be doing? There is the option of using the preprocessor but that seems messy to me. Someone also mentioned templates to me. What do you guys think?
If the virtual function calls become a problem, there is a compile time method that removes virtual calls using a small amount of preprocessor and a compiler optimization. One possible implementation is something like this:
Declare your base renderer with pure virtual functions:
class RendererBase {
public:
virtual bool Draw() = 0;
};
Declare a specific implementation:
#include <d3d11.h>
class RendererDX11 : public RendererBase {
public:
bool Draw();
private:
// D3D11 specific data
};
Create a header RendererTypes.h to forward declare your renderer based on the type you want to use with some preprocessor:
#ifdef DX11_RENDERER
class RendererDX11;
typedef RendererDX11 Renderer;
#else
class RendererOGL;
typedef RendererOGL Renderer;
#endif
Also create a header Renderer.h to include appropriate headers for your renderer:
#ifdef DX11_RENDERER
#include "RendererDX11.h"
#else
#include "RendererOGL.h"
#endif
Now everywhere you use your renderer refer to it as the Renderer type, include RendererTypes.h in your header files and Renderer.h in your cpp files.
Each of your renderer implementations should be in different projects. Then create different build configurations to compile with whichever renderer implementation you want to use. You don't want to include DirectX code for a Linux configuration for example.
In debug builds, virtual function calls might still be made, but in release builds they are optimized away because you are never making calls through the base class interface. It is only being used to enforce a common signature for your renderer classes at compile time.
While you do need a little bit of preprocessor for this method, it is minimal and doesn't interfere with the readability of your code since it is isolated and limited to some typedefs and includes. The one downside is that you cannot switch renderer implementations at runtime using this method as each implementation will be built to a separate executable. However, there really isn't much need for switching configurations at runtime anyway.
I use the approach with an abstract base class to the render device in my application. Works fine and lets me dynamically choose the renderer to use at runtime. (I use it to switch from DirectX10 to DirectX9 if the former is not supported, i.e. on Windows XP).
I would like to point out that the virtual function call is not the part which costs performance, but the conversion of the argument types involved. To be really generic, the public interface to the renderer uses its own set of parameter types such as a custom IShader and a custom Matrix3D type. No type declared in the DirectX API is visible to the rest of the application, as i.e. OpenGL would have different Matrix types and shader interfaces. The downside of this is really that I have to convert all Matrix and Vector/Point types from my custom type to the one the shader uses in the concrete render device implementation. This is far more expensive than the cost of a virtual function call.
If you do the distinction using the preprocessor, you also need to map the different interface types like this. Many are the same between DirectX10 and DirectX11, but not between DirectX and OpenGL.
Edit: See the answer in c++ Having multiple graphics options for an example implementation.
So, I realize that this is an old question, but I can't resist chiming in. Wanting to write code like this is just a side effect of trying to cope with object-oriented indoctrination.
The first question is whether or not you really need to swap out rendering back-ends, or just think it's cool. If an appropriate back-end can be determined at build time for a given platform, then problem solved: use a plain, non-virtual interface with an implementation selected at build time.
If you find that you really do need to swap it out, still use a non-virtual interface, just load the implementations as shared libraries. With this kind of swapping, you will likely want both engine rendering code and some performance intensive game-specific rendering code factored out and swappable. That way, you can use the common, high-level engine rendering interface for things done mostly by the engine, while still having access to back-end specific code to avoid the conversion costs mentioned by PMF.
Now, it should be said that while swapping with shared libraries introduces indirection, 1. You can easily get the indirection to be < to ~= that of virtual calls and 2. This high-level indirection is never a performance concern in any substantial game/engine. The main benefit is keeping dead code unloaded (and out of the way) and simplifying APIs and overall project design, increasing readability and comprehension.
Beginners aren't typically aware of this, because there is so much blind OO pushing these days, but this style of "OO first, ask questions never" is not without cost. This kind of design has a taxing code comprehension cost and leads to code (much lower-level than this example) that is inherently slow. Object orientation has its place, certainly, but (in games and other performance intensive applications) the best way to design that I have found is to write applications as minimally OO as possible, only conceding when a problem forces your hand. You will develop an intuition for where to draw the line as you gain more experience.
Related
I'm trying to write an abstraction layer to let my code run on different platforms. Let me give an example for two classes that I ultimately want to use in the high level code:
class Thread
{
public:
Thread();
virtual ~Thread();
void start();
void stop();
virtual void callback() = 0;
};
class Display
{
public:
static void drawText(const char* text);
};
My trouble is: What design pattern can I use to let low-level code fill in the implementation?
Here are my thoughs and why I don't think they are a good solution:
In theory there's no problem in having the above definition sit in highLevel/thread.h and the platform specific implementation sit in lowLevel/platformA/thread.cpp. This is a low-overhead solution that is resolved at link-time. The only problem is that the low level implementation can't add any member variables or member functions to it. This makes certain things impossible to implement.
A way out would be to add this to the definition (basically the Pimpl-Idiom):
class Thread
{
// ...
private:
void* impl_data;
}
Now the low level code can have it's own struct or objects stored in the void pointer. The trouble here is that its ugly to read and painful to program.
I could make class Thread pure virtual and implement the low level functionality by inheriting from it. The high level code could access the low level implementation by calling a factory function like this:
// thread.h, below the pure virtual class definition
extern "C" void* makeNewThread();
// in lowlevel/platformA/thread.h
class ThreadImpl: public Thread
{ ... };
// in lowLevel/platformA/thread.cpp
extern "C" void* makeNewThread() { return new ThreadImpl(); }
This would be tidy enough but it fails for static classes. My abstraction layer will be used for hardware and IO things and I would really like to be able to have Display::drawText(...) instead of carrying around pointers to a single Display class.
Another option is to use only C-style functions that can be resolved at link time like this extern "C" handle_t createThread(). This is easy and great for accessing low level hardware that is there only once (like a display). But for anything that can be there multiple times (locks, threads, memory management) I have to carry around handles in my high level code which is ugly or have a high level wrapper class that hides the handles. Either way I have the overhead of having to associate the handles with the respective functionality on both the high level and the low level side.
My last thought is a hybrid structure. Pure C-style extern "C" functions for low level stuff that is there only once. Factory functions (see 3.) for stuff that can be there multiple times. But I fear that something hybrid will lead to inconsistent, unreadable code.
I'd be very grateful for hints to design patterns that fit my requirements.
You don't need to have a platform-agnostic base class, because your code is only compiled for a single concrete platform at a time.
Just set the include path to, for example, -Iinclude/generic -Iinclude/platform, and have a separate Thread class in each supported platform's include directory.
You can (and should) write platform-agnostic tests, compiled & executed by default, which confirm your different platform-specific implementations adhere to the same interface and semantics.
PS. As StoryTeller says, Thread is a bad example since there's already a portable std::thread. I'm assuming there's some other platform-specific detail you really do need to abstract.
PPS. You still need to figure out the correct split between generic (platform-agnostic) code and platform-specific code: there's no magic bullet for deciding what goes where, just a series of tradeoffs between reuse/duplication, simple versus highly-parameterized code, etc.
You seem to want value semantics for your Thread class and wonder where to add the indirection to make it portable. So you use the pimpl idiom, and some conditional compilation.
Depending on where you want the complexity of your build tool to be, and if you want to keep all the low level code as self contained as possible, You do the following:
In you high level header Thread.hpp, you define:
class Thread
{
class Impl:
Impl *pimpl; // or better yet, some smart pointer
public:
Thread ();
~Thread();
// Other stuff;
};
Than, in your thread sources directory, you define files along this fashion:
Thread_PlatformA.cpp
#ifdef PLATFORM_A
#include <Thread.hpp>
Thread::Thread()
{
// Platform A specific code goes here, initialize the pimpl;
}
Thread::~Thread()
{
// Platform A specific code goes here, release the pimpl;
}
#endif
Building Thread.o becomes a simple matter of taking all Thread_*.cpp files in the Thread directory, and having your build system come up with the correct -D option to the compiler.
I am curious, what would it be like to design this situation like the following (just sticking to the thread):
// Your generic include level:
// thread.h
class Thread : public
#ifdef PLATFORM_A
PlatformAThread
#elif PLATFORM_B
PlatformBThread
// any more stuff you need in here
#endif
{
Thread();
virtual ~Thread();
void start();
void stop();
virtual void callback() = 0;
} ;
which does not contain anything about implementation, just the interface
Then you have:
// platformA directory
class PlatformAThread { ... };
and this will automatically result that when you create your "generic" Thread object you automatically get also a platform dependent class which automatically sets up its internals, and which might have platform specific operations, and certainly your PlatformAThread class might derive from a generic Base class having common things you might need.
You will also need to set up your build system to automatically recognize the platform specific directories.
Also, please note, that I have the tendency to create hierarchies of class inheritances, and some people advise against this: https://en.wikipedia.org/wiki/Composition_over_inheritance
I have had an idea for a non standard way to handle multiplatform interfaces in C++ and would like to know if that is generally a bad idea and why.
Currently I can only think of one disadvantage: It is very(?) uncommon do to something like that and maybe its not obvious how it works on first sight:
I have a class that will be used on different platforms, for example CMat4x4f32 (4x4 matrix class using 32 bit floats).
My platform independent interface looks like this:
class CMat4x4f32
{
public:
//Some methods
#include "Mat4x4f32.platform.inl"
};
Mat4x4f32.platform.inl looks like this:
public:
// Fills the matrix from a DirectX11 SSE matrix
void FromXMMatrix(const XMMatrix& _Matrix);
It just adds a platform depending interface to the matrix class.
The .cpp and the Mat4x4f32.platform.inl are located inside subfolders like "win32" or "posix" so in win32 I implement the FromXMMatrix function. My buildsystem adds these subfolders to the include path depending on the platform I build for.
I could even go a step beyond and implement a .platform.cpp that is located inside win32 and contains only the functions I add to the interface for that platform.
I personally think this is a good idea because it makes writing and using interfaces very easy and clean.
Especially in my Renderer library that heavily uses the Matrix class from my base library I can now use platform depending functions (FromXMMatrix) in the DirectX part as if I dont have any other platforms to worry about.
In the base library itself I can still write platform independent code using the common matrix interface.
I also have other classes where this is useful: For example an Error class that collects errors and automatically translates them into readable messages and provide some debugging options.
For win32 I can create error instances from bad DirectX and Win32 HResults and on Linux I can create them from returned errno's. In the base library I have a class that manages these errors using the common error interface.
It heavily reduces code required and prevents having ugly platform depending util classes.
So is this bad or good design and what are the alternatives?
It sounds like you're talking about using the bridge pattern:
http://c2.com/cgi/wiki?BridgePattern
In my personal experience I've developed a lot of platform independent interfaces, with specific implementations using this pattern and it has worked very well, I've often used it with the Pimpl idiom:
http://c2.com/cgi/wiki?PimplIdiom
As in alternatives I've found that this site in general is very good for explaining pros & cons of various patterns and paradigms:
http://c2.com/cgi/wiki
I would recommend you used "pimpl" instead:
class CMat4x4f32
{
public:
CMat4x4f32();
void Foo();
void Bar();
private:
std::unique_ptr<CMat4x4f32Impl> m_impl;
};
And then in build-file configs pull in platform specific .cpp files, where you for instance define your platform specific functions:
class CMat4x4f32::CMat4x4f32Impl
{
public:
void Foo() { /* Actual impl */ }
void Bar() { /* Actual impl */ }
// Fills the matrix from a DirectX11 SSE matrix
void FromXMMatrix(const XMMatrix& _Matrix);
};
CMat4x4f32::CMat4x4f32() : m_impl(new CMat4x4f32Impl()) {}
CMat4x4f32::Foo() { m_impl->Foo(); }
CMat4x4f32::Bar() { m_impl->Bar(); }
When I was younger, I used a tool called Game Maker a lot. I started to learn to program from it. I'm far beyond that now, but looking back on it, some of it's features and designs are quite interesting. I'm wondering- How would I implement functionality similar to this tool using C++?
I'm wondering about:
Objects/classes
Game Maker had a list of 'Objects' that you would create which were essentially just different classes all derived from the same base class (I'll call it GameObject for now) amd a system function called 'instance_create' that would take an object type as a paramater.
In c++ this would look something like this (Though syntatically very incorrect):
class MyGameObject : GameObject
{
//...
}
GameObject instance_create(class objecttype)
{
objecttype newinstance = new objecttype();
return newinstance
}
GameObject* gameobjectinstance = instance_create(MyGameObject);
How would I go about implementing that?
system variables/functions
Game Maker had system variables and functions that could be accessed from anywhere. Period. Anywhere. I'm thinking globals, but I know that's bad design. I'm thinking Having a global class, and have the variables/functions as static, but then they cannot be altered. How would I do that?
var
Game Maker had only one data type- a var. It could be a string, an integer, a decimal, anything. And there were system functions for conversion between those.
Lastly, how could I define the object types in some kind of script? Like, if I want to add a new type of object, create a new script? I don't think C++ can create object types at runtime, so how would I do this?
Using a template.
template<typename T> GameObject* instance_create()
{
return new T;
}
GameObject* gameobjectinstance = instance_create<MyGameObject>();
However, the design you have specified is highly questionable (at best) and definitely not suited to C++. You should strive to implement a well-designed system, and one appropriate to the language, not re-create a system from the past.
I especially think that since you mention run-time interpretation of scripts, that in fact the GameMaker classes and C++ classes have nothing to do with each other. And you definitely cannot create C++ classes at run-time, nor can you pass types around at run-time, nor can you instantiate templates at run-time.
You would be best suited simply whipping out a scripting language, such as Lua, and writing only the necessary high-performance components in C++.
Game Maker enables us to control game functionality through "objects", each composed out of "events", which are triggered at certain times during a game. Within events are "actions". Firstly, it's worth noting that comparing Game Maker development with C++ is like comparing chalk and cheese. However, theoretically speaking, I'd imagine you could mirror GM functionality (albeit very inefficiently) in C++ as follows:
The base object class could look something like this:
class CObjectBase
{
public:
CGameSprite* sprite;
int x, y;
...
virtual void onEventCreate( void ) {};
virtual void onEventDestroy( void ) {};
...
virtual void onEventKeyPressedUp( void ) {};
virtual void onEventKeyPressed...
...
... (there are lots of these)
// The draw event in GM (from memory) had in-built functionality:
virtual void onEventDraw( void )
{
CGameEngine::getSingleton()->DrawSpriteAtLocation( sprite, x, y );
}
};
You'd derive from this class and override the functions ("events") that are relevant to your object (the statements that compose these functions are your "actions"). Then there would be some sort of object instance manager singleton class which holds a list of all object instances in the current "room" and loops through each every frame (and handles instancing), triggering relevant events by calling their respective functions.
Interestingly, this actually roughly demonstrates why a system like Game Maker lacks a degree of efficiency. There is additional, unnecessary overhead that exists in order to keep options open for the developer. The bloated base object that all objects derive from is often overkill for specific situations. For example, imagine an object with just two events used out of 50 - the object manager still blindly checks for all these other events even if they aren't utilised. Obviously optimisations can be made, but overall, the breadth of the engine ultimately results in reduced performance.
As for your query relating to a single 'var' type, as has been stated already, this is more a characteristic of scripting, not C++. This proves that Game Maker cannot simply be modeled by C++ alone.
I have a chess variants engine that plays suicide chess and losers chess along with normal chess. I might, over time, add more variants to my engine. The engine is implemented completely in C++ with proper usage of OOP. My question is related to design of such a variant engine.
Initially the project started as a suicide-only engine while over time I added other flavors. For adding new variants, I experimented using polymorphism in C++ first. For instance, a MoveGenerator abstract class had two subclasses SuicideMoveGenerator and NormalMoveGenerator and depending on the type of game chosen by user, a factory would instantiate the right subclass. But I found this to be much slower - obviously because instantiating classes containing virtual functions and calling virtual functions in tight loops are both quite inefficient.
But then it occurred to me to use C++ templates with template specialization for separating logic for different variants with maximum reuse of code. This also seemed very logical because dynamic linking is not really necessary in the context as once you choose the type of game, you basically stick with it until the end of the game. C++ template specialization provides exactly this - static polymorphism. The template parameter is either SUICIDE or LOSERS or NORMAL.
enum GameType { LOSERS, NORMAL, SUICIDE };
So once user selects a game type, appropriate game object is instantiated and everything called from there will be appropriately templatized. For instance if user selects suicide chess, lets say:
ComputerPlayer<SUICIDE>
object is instantiated and that instantiation basically is linked to the whole control flow statically. Functions in ComputerPlayer<SUICIDE> would work with MoveGenerator<SUICIDE>, Board<SUICIDE> and so on while corresponding NORMAL one will appropriately work.
On a whole, this lets me instantiate the right templatize specialized class at the beginning and without any other if conditions anywhere, the whole thing works perfectly. The best thing is there is no performance penalty at all!
The main downside with this approach however is that using templates makes your code a bit harder to read. Also template specialization if not appropriately handled can lead to major bugs.
I wonder what do other variant engine authors normally do for separation of logic (with good reuse of code)?? I found C++ template programming quite suitable but if there's anything better out there, I would be glad to embrace. In particular, I checked Fairymax engine by Dr. H G Muller but that uses config files for defining game rules. I don't want to do that because many of my variants have different extensions and by making it generic to the level of config-files the engine might not grow strong. Another popular engine Sjeng is littered with if conditions everywhere and I personally feel thats not a good design.
Any new design insights would be very useful.
"Calling virtual functions in tight loops are inefficient"
I would be pretty surprised actually if this caused any real bloat, if all the variables of the loop have the same dynamic type, then I would expect the compiler to fetch the corresponding instruction from its L1 cache and thus not suffer much.
However there is one part that worries me:
"obviously because instantiating classes containing virtual functions [is] quite inefficient"
Now... I am really surprised.
The cost of instantiating a class with virtual functions is near undistinguishable from the cost of instantiating a class without any virtual functions: it's one more pointer, and that's all (on popular compilers, which corresponds to the _vptr).
I surmise that your problem lies elsewhere. So I am going to take a wild guess:
do you, by any chance, have a lot of dynamic instantiation going on ? (calling new)
If that is the case, you would gain much by removing them.
There is a Design Pattern called Strategy which would be eminently suitable for your precise situation. The idea of this pattern is akin, in fact, to the use of virtual functions, but it actually externalize those functions.
Here is a simple example:
class StrategyInterface
{
public:
Move GenerateMove(Player const& player) const;
private:
virtual Move GenerateMoveImpl(Player const& player) const = 0;
};
class SuicideChessStrategy: public StrategyInterface
{
virtual Move GenerateMoveImpl(Player const& player) const = 0;
};
// Others
Once implemented, you need a function to get the right strategy:
StrategyInterface& GetStrategy(GameType gt)
{
static std::array<StrategyInterface*,3> strategies
= { new SuicideChessStrategy(), .... };
return *(strategies[gt]);
}
And finally, you can delegate the work without using inheritance for the other structures:
class Player
{
public:
Move GenerateMove() const { return GetStrategy(gt).GenerateMove(*this); }
private:
GameType gt;
};
The cost is pretty much similar to using virtual functions, however you do not need dynamically allocated memory for the basic objects of your game any longer, and stack allocation is a LOT faster.
I'm not quite sure if this is a fit but you may be able to achieve static polymorphism via the CRTP with some slight modifications to your original design.
First of all I have to mention that I have read many C++ virtual questions in on stackoverflow. I have some knowledge how they work, but when I start the project and try to design something I never consider/use virtual or pure virtual implementations. Maybe it is because I am lack of knowledge how do they work or I don't know how to realize some stuff with them. I think it's bad because I don't use fully Object Oriented development.
Maybe someone can advise me how to get used to them?
Check out abstract base classes and interfaces in Java or C# to get ideas on when pure virtuals are useful.
Virtual functions are pretty basic to OO. Theree are plenty of books out there to help you. Myself, I like Larman's Applying UML and Patterns.
but when I start the project and try to design something I never consider/use virtual or pure virtual implementations.
Here's something you can try:
Figure out the set of classes you use
Do you see some class hierarchies? A Circle is-a Shape sort of relationships?
Isolate behavior
Bubble up/down behavior to form interfaces (base classes) (Code to interfaces and not implementations)
Implement these as virtual functions
The responsibility of defining the exact semantics of the operation(s) rests with the sub-classes'
Create your sub-classes
Implement (override) the virtual functions
But don't force a hierarchy just for the sake of using them. An example from real code I have been working on recently:
class Codec {
public:
virtual GUID Guid() { return GUID_NULL; }
};
class JpegEncoder : public Codec {
public:
virtual GUID Guid() { return GUID_JpegEncoder; }
};
class PngDecoder : public Codec {
public:
virtual GUID Guid() { return GUID_PngDecoder; }
};
I don't have a ton of time ATM, but here is a simple example.
In my job I maintain and application which talks to various hardware devices. Of these devices, many motors are used for various purposes. Now, I don't know if you have done any development with motors and drives, but they are all a bit different, even if they claim to follow a standard like CANOpen. Anyway, you need to create some new code when you switch vendors, perhaps you motor or drive was end-of-life'd, etc. On top of that, this code has to maintain compatibility with older devices, and we also have various models of similar devices. So, all in all, you have to deal with many different motors and interfaces.
Now, in the code I use an abstract class, named "iMotor", which contains only pure virtual functions. In the implementation code only the iMotor class is referenced. I create a dll for different types of motors with different implementations, but they all implement the iMotor interface. So, all that I need to do to add/change a motor is create a new implementation and drop that dll in place of the old one. Because the code which uses these motor implementations deals only with the iMotor interface it never needs to change, only the implementation of how each motor does what it does needs to change.
If you google for design patterns like the "strategy pattern" and "command pattern" you will find some good uses of interfaces and polymorphism. Besides that, design patterns are always very useful to know.
You don't HAVE to use them but they have their advantages.
Generally they are used as an "interface" between 2 different types of functionality that, code wise, aren't very related.
An example would be handling file loading. A simple file handling class would seem to be perfect. However at a later stage you are asked to shift all your files into a single packaged file while maintaining support for individual files for debug purposes. How do you handle loading here? Obviously things will be handled rather differently because suddenly you can't just open a file. Instead you need to be able to look up the files location and then seek to that location before loading, pretty much, as normal.
The obvious thing to do is implement an abstract base class. Perhaps call it BaseFile. The OpenFile function handling will differ dependent on whether you are using the PackageFile or the DiskFile class. So make that a pure virtual.
Then when you derive the PackageFile and DiskFile classes you provide the appropriate implementation for Opening a file.
You can then add something such as
#if !defined( DISK_FILE ) && defined ( _DEBUG )
#define DISK_FILE 1
#elif !defined( DISK_FILE )
#define DISK_FILE 0
#endif
#if DISK_FILE
typedef DiskFile File;
#else
typedef PackageFile File;
#endif
Now you would just use the "File" typedef to do all file handling. Equally if you don't pre-define DISK_FILE as 0 or 1 and debug is set it will automatically load from disk otherwise it will load from the Package file.
Of course such a construct still allows you to load from the Package file in debug simply by defining DISK_FILE to be 1 in advance and it also allows you to use disk access in a release build by setting DISK_FILE to 0.