I want to create a game engine as a training & portfolio project and the modular approach sounds promising but I have some problems with the module design.
First I want to create low level modules like Rendering, Application, Utility etc. and use them in high level modules like Terrain.
So the dependency would kinda look like this Game<-Engine<-Terrain<-Rendering.
I want to create multiple Rendering "sub modules" like Rendering.Direct3D11 and Rendering.OpenGL. That's where I would have circular dependencies. The sub modules would use interfaces of Rendering and Rendering would need to manage the sub modules, right?
Game<-Engine<-Terrain<-Rendering<-->Rendering.Direct3D11
I could probably create a module like RenderingInterfaces and break the circular dependency but that seems like a hacky workaround. I was planning to use the "sub module design" multiple times like for:
Game<-Engine<-Application<-->Application.Windows
Is the sub module design ugly? Is there a way to use the sub module design without circular dependencies?
You can solve this abstractly. Let's say you have three dylibs: Game.dll, Renderer.dll, SubRenderer.dll.
The renderer interface might look like this (simplified):
// Renderer.h
class SubRenderer
{
public:
virtual ~SubRenderer() {}
virtual void render() = 0;
};
class API Renderer
{
public:
explicit Renderer(SubRenderer* sub_renderer);
void render();
private:
SubRenderer* sub_renderer;
};
You can stick that in Renderer.h or something like that, and the Renderer constructor and render method can be implemented in Renderer.cpp which you include for the project that outputs Renderer.dll.
Now in SubRenderer.dll, you might have a function like this:
// SubRenderer.h
class SubRenderer;
API SubRenderer* create_opengl_renderer();
That can be implemented in SubRenderer.cpp which is compiled/linked to output `SubRenderer.dll. It might look like this:
// SubRenderer.cpp
#include "SubRenderer.h"
#include <Renderer.h>
class OpenGlRenderer: public SubRenderer
{
public:
virtual void render() override {...}
};
SubRenderer* create_opengl_renderer()
{
return new OpenGlRenderer;
}
Last but not least, in some source file in Game.dll, you can do something like this inside some Game.cpp:
// Game.cpp
#include <Renderer.h>
#include <SubRenderer.h>
int main()
{
SubRenderer* opengl_renderer = create_opengl_renderer();
Renderer renderer(opengl_renderer);
renderer.render(); // render a frame
...
delete opengl_renderer;
}
... of course hopefully with a safer design that conforms to RAII.
With this kind of system, you have these header dependencies:
`Game.cpp->Renderer.h`
`Game.cpp->SubRenderer.h`
`SubRenderer.cpp->Renderer.h`
In terms of module dependencies:
`Game.dll->Renderer.dll`
`Game.dll->SubRenderer.dll`
And that's it -- no circular dependencies anywhere. Game.dll depends on Renderer.dll and SubRenderer.dll, but Renderer.dll and SubRenderer.dll are completely independent of each other.
This works because this Renderer can use a SubRenderer given its virtual interface without knowing exactly what it is (thus requiring no dependencies to the concrete type of 'sub-renderer').
You can put Renderer.h somewhere that is centrally accessible from all three projects with a common include path (ex: inside an SDK directory). There is no need to duplicate it.
There shouldn't be any need for a reverse dependency in your design.
This is all about interfaces. Your rendering module need a native rendering API (sub-module, in your terms), but it shouldn't care if it is OpenGL or Direct3D11. The API sub-modules just have to expose a common API ; something like CreatePrimitiveFromResource(), RenderPrimitive()... These sub-modules shouldn't be aware of the upper layer, they just expose their common API.
In other words, the only "dependencies" needed is that the rendering module depends on a rendering sub-module (using the common interface), and the rendering sub-modules don't depend on anything (in your engine), they just expose a common interface.
Simple example :
We have a rendering module "IntRenderer" that renders integers. Its job is to convert integers to characters and print them. Now we want to have sub-modules "IntRenderer.Console" and "IntRenderer.Window", to print in a console or in a window.
With that, we define our interface : the sub-module must be a DLL that exports a function void print( const char * );.
This whole description is our interface ; it describes a common public face that all our int renderers sub-modules must have. Programmatically, you could say that the interface is just the function definition, but that's just a matter of terminology.
Now each sub-module can implement the interface :
// IntRenderer.Console
DLLEXPORT void print( const char *str ) {
printf(str);
}
// IntRenderer.Window
DLLEXPORT void print( const char *str ) {
AddTextToMyWindow(str);
}
With that, the int renderer can just use import a sub-module, and use printf(myFormattedInt);, regardless of the sub-module.
You can obviously define your interface as you want, with C++ polymorphism if you want.
Example : sub-modules X must be a DLL that exports a function CreateRenderer() that returns a class that inherit the class Renderer, and implements all its virtual functions.
Related
I'm trying to create simple game in C++. At one point I want to have some setting, save and load from config file.
The config file should be read from the beginning, and should be accessible anywhere it needed.
So far I only see Singleton pattern as a solution.
Another way is to create an object an pass it down, but it can mess
up the current code.
I've also search and found something called Dependency Injection.
Is dependency injection useful in C++
Which design patterns can be applied to the configuration settings problem?
But I don't quite understand it, you still have to create an object in main and pass it down, right?
Singleton is quite simple, but some consider it antipattern, while pass it down the tree can mess up my current code. Is there any other Patterns?
P/S: I'm also curious how games load their setting.
I would suggest something simple as the following example, which circumvents any singleton-related or initialization order issue:
struct global_state
{
config _config;
};
struct game_state
{
global_state& _global_state;
};
int main()
{
global_state globals{load_config_from_file()};
game_state game{globals};
game.run();
}
Since _global_state is a member of game_state, it can be used in member functions without the need of explicitly passing it as a parameter:
void game_state::update_ui()
{
const float text_size = _global_state._config.get_float("text_size");
_some_text.set_size(text_size);
}
I am trying to understand project structure in c++, I am finding it difficult to get my head around class structure and header files.
Extract from article 1 (linked at bottom of this post)
By convention, include directory is for header files, but modern practice > suggests that include directory must strictly contain headers that need
to be exposed publicly.
My first question of this process is with regards to a separate class file that is within the include directory.
What is purpose of exposing your headers?
Following on from this, looking at an example of an exposed header file. Linked in the following GH repo: https://github.com/AakashMallik/sample_cmake
How does the Game_Interface class relate back to the Game_Engine?
game_interface.h
#pragma once
#include <game_engine.h>
class GameInterface
{
private:
GameEngine *game;
public:
GameInterface(int length);
void play(int num);
};
I have looked else where for a simple explanation of this process but, all I have found so far is nothing that can be understood in the context of this example.
Fairly new to C++ background in web technologies.
Link to article 1: https://medium.com/heuristics/c-application-development-part-1-project-structure-454b00f9eddc
What is purpose of exposing your headers?
Sometimes you may be developing some functionality or a library. You might want to help some other person or customer or client by sharing the functionality of your code. But you don't want to share the exact working details.
So for instance you wish to share an Image processing functionality which applies beautiful filters to it. But at the same time you don't want them to exactly know how did you implement it. for such scenarios, you can create a header file, say img_filter.h having function declaration -
bool ApplyFilter(const string & image_path);
Now you can implement entire details in img_filter.cpp:
bool ApplyFilter(const string & image_path)
{
....
// Implementation detail
...
}
Next you can prepare a dll of this file which could be used by your client. For reference of working, parameters, usage etc. you can share the img_filter.h.
Relation with Interface:
A well defined interface is generally nice to have so you can change implementation details transparently, which means, that HOW you implement the details don't matter as long as the interface or the function name and parameters are kept intact.
I am currently developing on a Chromium Embedded framework app.
The project consists of a client and a helper. I need to know the bundle path from the helper, easy just use the methods of foundation.... Well I can't since I can't use foundation in the helper.
The client is a C++ based core wrapped in a objective-c++ cocoa app.
The helper is pure C++.
The two apps share an custom class for process-type-based behaviour ( see code below). The "OnBeforeCommandLineProcessing" method needs to use the bundle path! (Just changing file ending to .mm and importing foundation/cocoa does not work, as soon as i import foundation things turn ugly with a huge amount of errors). How can I get bundle path from C++ without foundation? This does not work: mainBundle = CFBundleGetMainBundle();
namespace client {
// Base class for customizing process-type-based behavior.
class ClientApp : public CefApp {
public:
ClientApp();
enum ProcessType {
BrowserProcess,
RendererProcess,
ZygoteProcess,
OtherProcess,
};
// Determine the process type based on command-line arguments.
static ProcessType GetProcessType(CefRefPtr<CefCommandLine> command_line);
protected:
// Schemes that will be registered with the global cookie manager.
std::vector<CefString> cookieable_schemes_;
private:
// Registers custom schemes. Implemented by cefclient in
// client_app_delegates_common.cc
static void RegisterCustomSchemes(CefRefPtr<CefSchemeRegistrar> registrar,
std::vector<CefString>& cookiable_schemes);
void OnBeforeCommandLineProcessing(const CefString& process_type,
CefRefPtr<CefCommandLine> command_line) OVERRIDE;
// CefApp methods.
void OnRegisterCustomSchemes(
CefRefPtr<CefSchemeRegistrar> registrar) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(ClientApp);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_COMMON_CLIENT_APP_H_
Trying to import cocoa/foundation after renaming to .mm:
You're importing Foundation.h when you mean #include <CoreFoundation/CoreFoundation.h>. Foundation is an ObjC API (which is not compatible with C++). Core Foundation is a C API. When you include CoreFoundation, CFBundleGetMainBundle() should be fine. Note the CF at the start that is indicating it's part of Core Foundation, vs NS which indicates Foundation (or AppKit).
There is no need to rename this .mm. As long as you use CoreFoundation, it's fine to be a pure C++ file. Just remember that Core Foundation has its own memory management. There is no ARC. You need to remember to CFRelease anything you obtained using a function with Create or Copy in its name (or that you called CFRetain on. Full details are in the Memory Management Programming Guide for Core Foundation.
I have C++ solution with some apps and static libraries:
UserRace1.exe
UserRace2.exe
GreenBody.lib
BlueBody.lib
RedBody.lib
BigWheels.lib
MiddleWheels.lib
SmallWheels.lib
V8Engine.lib
V12Engine.lib
RaceTires.lib
WinterTires.lib
SimpleTires.lib
Garage.lib
In application, I just simulate race, one application for each race. Libs consist classes that describe parts of the car (body, wheels, engine, etc.). Every class implement some interface (IBody, IWheels, IEngine, etc.), that described in Garage lib. And Garage.lib should create cars, using parts.
So, I pass car parameters to application, as example: -Car1 -RedBody -MiddleWheels -V8Engine -RaceTires -Car2 -BlueBody -SmallWheels -V12Engine -WinterTires . Application call Garage class: Garage::GetCar(string body, string wheels, string engine, string tires) and garage return Car object, that we use in app. Pay attention, that I pass this arguments like a string. It's important.
Now, about what I want. I write only Garage lib. Other libs will be write by other people. And I want my library has been universal. At this moment, when new part added (e.g. BlackBody.lib) I must add support of this in my Garage.lib. something like:
...
else if (body == "RedBody")
{
car->body = new RedBody();
}
else if (body == "BlackBody")
{
car->body = new BlackBody();
}
...
But I want to get this types dynamicaly. Like:
foreach (Librarian lib in Application.GetLibs())
{
foreach (Type type in lib)
{
if (type is IBody)
{
if (((IBody)type)::GetColor() == color)
{
car->body = type.GetInstance();
return;
}
}
}
}
Then, if someone add new type, I will not change my library. Problem is, that I write on C++, not C#. And I don't know how to implement it.
Maybe I should use dll instead of static lib? Is this an only way? And if so, whether there would be problems that the applications and dlls use one library (Garage.lib)? Cause they use different runtime libraries (/MT and /MD).
You could have an entirely "dynamic" solution, using DLLs, provided that:
you could derive a Dll name ("BlackBody.dll") from a string '"BlackBody")
each Dll exports a factory function, with a predictable name ("Factory", or "BlackBodyFactory")
You dynamically load the Dlls, and get the factory pointer function via GetProcAddress
your Garage.lib code only knows about the Body base class, because that's what a "body" factory function will return
You should avoid mixing different CRT in the same process. Mixing is possible but involves extra care/work.
I am currently writing an application that will serve a similar purpose for multiple clients, but requires adaptations to how it will handle the data it is feed. In essence it will serve the same purpose, but hand out data totally differently.
So I decided to prodeed like this:
-Make common engine library that will hold the common functionalities of all ways and present the default interface ensuring that the different engines will respond the same way.
-Write a specific engine for each way of functioning....each one compiles into its own .dll.
So my project will end up with a bunch of libraries with some looking like this:
project_engine_base.dll
project_engine_way1.dll
project_engine_way2.dll
Now in the configuration file that we use for the user preferences there will an engine section so that we may decide which engine to use:
[ENGINE]
Way1
So somewhere in the code we will want to do:
If (this->M_ENGINE == "Way1")
//load dll for way1
Else If (this->M_ENGINE == "Way2")
//load dll for way2
Else
//no engines selected...tell user to modify settings and restart application
The question is...How will I import my dll(s) this way? Is it even possible? If not can I get some suggestions on how to achieve a similar way of functioning?
I am aware I could just import all of the dlls right at the start and just choose which engine to use, but the idea was that I didn't want to import too many engines for nothing and waste resources and we didn't want to have to ship all of those dlls to our customers. One customer will use one engine another will use a different one. Some of our customer will use more than one possibly hence the reason why I wanted to externalize this and allow our users to use a configuration file for engine switching.
Any ideas?
EDIT:
Just realized that even though each of my engine would present the same interface if they are loaded dynamically at runtime and not all referenced in the project, my project would not compile. So I don't have a choice but to include them all in my project don't I?
That also means they all have to be shipped to my customers. The settings in the configuration would only dictate with class I would use to initialize my engine member.
OR
I could have each of these engines be compiled to the same name. Only import one dll in my main project and that particular engine would be used all the time. That would render my customers unable to use our application for multiple clients of their own. Unless they were willing to manually switch dlls. Yuck
Any suggestions?
EDIT #2:
At this point seeing my options, I could also juste make one big dll containing the base engine as well as all the child ones and my configuration to let the user chose. Instead of referencing multiple dlls and shipping them all. Just have one huge one and ship/reference that one only. I am not too fond of this either as it means shipping one big dll to all of my customers instead of just one or two small ones that suit there needs. This is still the best solution that I've come up with though.
I am still looking for better suggestions or answers to my original question.
Thanks.
Use separate DLLs for each engine and use LoadLibrary in your main project to load the specific engine based on the configuration.
Have your engine interface in some common header file that all engines will derive from and this interface will be used in your main project aswell.
It might look like this:
// this should be an abstract class
class engine {
public:
virtual void func1() = 0;
virtual void func2() = 0;
...
};
In each different engine implementation export a function from the DLL, something like this:
// might aswell use auto_ptr here
engine* getEngine() { return new EngineImplementationNumberOne(); }
Now in your main project simply load the DLL you're interested in using LoadLibrary and then GetProcAddress the getEngine function.
string dllname;
if (this->M_ENGINE == "Way1")
dllname = "dllname1.dll";
else if (this->M_ENGINE == "Way2")
dllname = "dllname2.dll";
else
throw configuration_error();
HMODULE h = LoadLibraryA(dllname.c_str());
typedef engine* (*TCreateEngine)();
TCreateEngine func = (TCreateEngine)GetProcAddress(h, "getEngine");
engine* e = func();
The name of the exported function will probably get mangled, so you could either use DEF files or extern "C" in your DLLs, also don't forget to check for errors.
The solution I came to is the following:
Engine_Base^ engine_for_app;
Assembly^ SampleAssembly;
Type^ engineType;
if (this->M_ENGINE == "A")
{
SampleAssembly = Assembly::LoadFrom("path\\Engine_A.dll");
engineType = SampleAssembly->GetType("Engine_A");
engine_for_app = static_cast<Engine_Base^>(Activator::CreateInstance(engineType, param1, param2));
}
else
{
SampleAssembly = Assembly::LoadFrom("path\\Engine_B.dll");
engineType = SampleAssembly->GetType("Engine_B");
engine_for_app = static_cast<Engine_Base^>(Activator::CreateInstance(engineType, param1, param2, param3, param4));
}
I used the answer from Daniel and the comments that were made on his answer. After some extra research I came across the LoadFrom method.