Application

Application Structure

All applications in Force holds by Force::Application class. Application is base class of Force Engine, it holds all user applications, install other engines, managers, load libraries defined by ApplicationSpecification.

To create a application we need create single executable .cpp file, in our case in will be ExampleApplication.cpp.

Then you need to include Force API to get access to engine functionality. You can do it multiple ways for example by including Force.h or ForceMinInclude.h and then Main.cpp. But this is not recommended even if it will work. We will do it properly by creating Config.h file, that you can copy from engine Config.h with all description about each define.

So this how our Config file should looks like:

#pragma once

// [Should Defined]: User defined choice to include full Force API. (Force.h).
// If you define this Force will include 'Force.h' file in 'Main.cpp'.
//
// 
// #define FE_CONFIG_INCLUDE_FORCE 

// [Should Defined]: Alternative choice to include Force. If you define this instead including all Force files
// it will include only minimum core files that need to write custom applications, then to
// get access to other modules such a Graphics, Scripting or SceneManagment, you need include
// it by yourself.
//
// 
#define FE_CONFIG_INCLUDE_FORCE_MIN 

// This is entry point of each of Force application. It should be defined otherwise you cannot compile Force Application.
#include "Force/Main.cpp"

In this config file we can choose how include Force. By defining FE_CONFIG_INCLUDE_FORCE all force public API will be included to ExampleApplication. By defining FE_CONFIG_INCLUDE_FORCE_MIN only minimum requered API will be inlcuded, so for ExampleApplication we choose it. By defining other controlling config stuff see Config.h that stored in Force/Sources.

Now how our ExampleApplication.cpp file should looks like:

#include "Config.h"

Any Application accept the ApplicationSpecification structure in their base constructor. About the specifications we will talk later.

// Defenition of Application constructor.
Application(const ApplicationSpecification& spec);

Each Force Core module is divided by different folder and stored in namespaces. Here list with all supported at this moment Force modules.

Module
Folder
Namespace

Core

Force/Core

Force::Core

IO

Force/IO

Force::IO

Graphics

Force/Graphics

Force::Graphics

Graphics (OpenGL)

Force/Graphics/GL

Force::Graphics::GL

Graphics (DirectX)

Force/Graphics/D3D

Force::Graphics:D3D

Audio

Force/Audio

Force::Audio

Platform

Force/Platform

Force::Platform

Physics

Force/Physics

Force::Physics

Math

Force/Math

Force::Math

Assets

Force/Assets

Force::Assets

Project

Force/ProjectManagment

Force::ProjectManagment

Scene Managment

Force/SceneManagment

Force::SceneManagment

Scripting

Force/Scripting

Force::Scripting

Serialization

Force/Serialization

Force::Serialization

Localization

Force/Localization

Force::Localization

Utils

Force/Utils

Force::Utils

Let's start with Force namespace. This is the most important folder where the engine main modules, are stored.

Force::Core is designed for the engine core. it stores all the most important things for the engine and your application.

Next the Force::IO namespace where events, input, and output are stored.

In Force::Graphics as you have already understood everything is stored related to graphics, graphics engines, and so on. Inside it there are namespaces ::GL,::D3D that display each API. You don't need to use them this is only for the engine developers side.

Force::Audio designed for audio and store the Audio Engine.

Force::Platform stores different system that specific for each platform. You won't need to use it, either.

What you will need to use quite often so it Force::Math. This namespace stores vectors, matrices, and all that crap about math and computing.

Force::Assets namespace store all files that need to work with assets and asset system in general.

Force::Scripting is namespace that store all Mono scripting engine code, and need only for engine developers.

Force::Localization is localization / language manager module.

Force::Serializaionis serialization/de-serialization manager module.

Force::Utils is namespace that store all utilities files for platform, or from standard of C++ or from other libraries.

For base executable files such ExampleApplication its recommended to directly use Force API with namespaces, but for other files you can just defined it.

Note if you not use Config.h file you should also include Main.cpp file after Config.h.

#include "Force/Main.cpp"

Each application should have its entry point. Entry point is entry of any program in general. In Force entry point defined in Main.cpp file. Without it, you won't be able to compile and launch the application. This file need to be included once per application project.

Before launching application we need to create implementation of Force::CreateApplication() function.


Force::Application* Force::CreateApplication(const Force::ApplicationBootSpecffication& bootSpec) noexcept {
    ApplicationSpecification applicationSpec;
    applicationSpec.name = "Example Application";
    applicationSpec.workingPath = "C:/ForceDev/Examples/ExampleApplication";
    applicationSpec.resourcesDir = "Resources";
    
    Force::Application* application = new Force::Application(applicationSpec);
    return application;
}

And that's it! One of base and main things, we have done everything. Now you can just press F5 and build and run your own application written in Force.

If you have some problems with compiling or linking Force, please take a look on the latest two chapters below.

Application Specifications

Now Applications use the specifications like ApplicationSpecification, ApplicationUserSpecification, ApplicationWindowSpecification, and ApplicationBootSpecification instead old GetParam API.

When you first configure and run the engine you will have by default are the default settings of window and so on. If you want to add or change your app's settings you will need to use Force::ApplicationSpecification struct to configurate custom application. Its contains the bunch options that you can apply on application.

ApplicationSpecification

struct ApplicationSpecification {
   const wchar_t*                   nameWide        = FE_NULLPTR;                      // Wide Char Name of the application.
   String                           name;                                              // Name of the application.
   String                           description;                                       // Description of the application.
   String                           autor;                                             // Autor/company of product/application.
   String                           version;                                           // Version of application. Defines in string as 0.0.1.
   uint                             versionMajor;                                      // Seperate major version.
   uint                             versionMinor;                                      // Seperate minor version.
   ApplicationVersionType           versionType      = ApplicationVersionType_Release; // Type of the application version. Usefull for developing.
   Path                             workingPath;                                       // Working directory of project.
   Path                             resourcesDir;                                      // Directory of working resources.
   ApplicationBootSpecification     bootSpec;                                          // Additional create/command line specification.
   ApplicationWindowSpecification   windowSpec;                                        // Additional window specification.
   ApplicationUserSpecification     userSpec;                                          // Additional user specification.
   ApplicationPlatformSpecification platformSpec;                                      // Platfrom application specification.
   ApplicationBuildSpecification*   buildSpec;                                         // Build specification. Used for retriving build scene list to output application.
   ApplicationHook                  hook;                                              // Application Hooks.
   bool                             consoleApp       = FE_FALSE;                       // If true Force will create windowless application, with only console and force cut off: any main surface/window, LogoScreen, IO Engine, Render Engine, Language Manager, Scene Manager, Asset Manager, Drag Drop, VFS. This usefull for blank empty applications or audio applications, or servers. NOTE: If this was set you cannot undo in runtime on you client side (Application, Element, etc) this until application reloading.
   bool                             launchInIDE;                                       // Special flag for running app throw IDE or final excecutable.
   bool                             logoScreen       = FE_FALSE;                       // [Beta]: If this true application during loading its resources will show the logo screen. NOTE: Modifying this after application creation is not allowed.
   bool                             useImGuiElement  = FE_FALSE;                       // If true Force will create Dear's ImGui context and process it on their element. 
   bool                             useForceRenderer = FE_TRUE;                        // Enable the Force rendering engine. For all cases should be true, only for example if you want to render only throw custom render engine or Dear's ImGui shell. NOTE: Modifying this after application creation is not allowed.
   bool                             useForceAudio    = FE_TRUE;                        // Enable the Force audio engine. Should be false only if your never will use Audio Engine in your Application. NOTE: Modifying this after application creation is not allowed.
   bool                             useStdTerminate  = FE_TRUE;                        // [Debug]: If this true will set global exception function handler (works outside VS only), or throw regular try..catch block.
};

As you can see ApplicationSpecification contains basic, parameter as name or version of your app, but also contains other application sub-specifications.

ApplicationUserSpecification

User specification contains information about user per application. Some of options can be independent of each application, like startProjectPath or newUser.

But other options is specific for each application.

struct ApplicationUserSpecification {
  UUID ID;
  bool newUser;
  bool dist;                // Returns true if ForceEngine runs as Distrubution build, otherwise Dev build.
  Path applicationPath;     // Path where Application.exe is stored.
  Path lastApplicationPath; // Path where Application.exe was storing on disk from prev session.
  Path startProjectPath;    // Path where last project is stored or start path or project.
  UUID startScene = 0;      // UID of startup scene, relative to startProjectPath Assets directory.
};

ApplicationWindowSpecification

Window specification contains application window info.

struct ApplicationWindowSpecification {
  String name          = "My Window";                   // Name of the window not affected on its title.
  String title         = "My Window Title";             // Initial title of the window. Name != Title. Title can be modified by Name not.
  uint   xPos          = 0;                             // Initial X coordinate of the window relative to OS window coordinates. 
  uint   yPos          = 0;                             // Initial Y coordinate of the window relative to OS window coordinates.       
  uint   width         = 1280;                          // Initial width of the window.
  uint   height        = 720;                           // Initial height of the window.
  uint   minWidth      = 0;                             // Minimum width of the window, window X size cannot be below this width. 
  uint   minHeight     = 0;                             // Minimum height of the window, window Y size cannot be below this height. 
  bool   centered      = FE_TRUE;                       // Ignore the initial xPos, yPos, and centered window on creation.
  float  aspectRatio   = (float)width / (float)height;
  bool   resizeble     = FE_TRUE;                       // Has a maximize box, resize drip and can be resized?
  bool   maximized     = FE_FALSE;                      // Maximize window on creation. Window also can be Maximized the window by one of Show.
  bool   visible       = FE_TRUE;                       // Check if window visible of not.Initialy sets to FE_TRUE, but can be modified by WindowFlags_SetInitialVisible during creation.
  bool   topmost       = FE_FALSE;                      // Set the window on top of others. Initialy sets to FE_FALSE, but can be modified by WindowFlags_Topmost.
  bool   fullscreen    = FE_FALSE;
  bool   vSync         = FE_FALSE;
  Path   iconPath      = Path();                        // Path to window icon file. 
  Path   iconSmallPath = Path();                        // Path to small window icon file. 
  Path   iconLogoPath  = Path();                        // Path to logo window texture if application use logo window.
  bool   darkTheme     = FE_FALSE;                      // Change the title bar color to dark. Works only if that platfrom support it.
  bool   blank         = FE_FALSE;                      // [BETA API]: Make a blank window without title bar, maximize, minimized, close button. This style will block: decorated and resizeble settings.
  bool   decorated     = FE_TRUE;                       // Set the widnow decorated [with additional decorations or blank window]. Initialy sets to FE_TRUE, but can be modified by WindowFlags_NoDecorated.
};

ApplicationBootSpecification

Contains information about boot/start data that comes from Core and Entry Point.

struct ApplicationBootSpecification {
  ArrayList<String> cmdLineArgs;
  PlatformAPI       platfromAfterReset;
  RendererAPI       rendererAfterReset;
};

This Application specification you should implement in your CreateApplication function. For example:

Force::Application* Force::CreateApplication(const Force::ApplicationBootSpecification& bootSpec) noexcept {
  ApplicationSpecification applicationSpec;
  applicationSpec.name = "Example Application";
  applicationSpec.autor = "Danil Dukhovenko";
  applicationSpec.description = "This is example app.";
  applicationSpec.version = "0.0.1";
  applicationSpec.versionMajor = 0;
  applicationSpec.versionMinor = 1;
  applicationSpec.workingPath = "C:\\Force\\ExampleApplication";
  applicationSpec.resourcesDir = "Resources\\ExampleApplication";
  applicationSpec.windowSpec.width = 1280;
  applicationSpec.windowSpec.height = 720;
  applicationSpec.windowSpec.minWidth = 640;
  applicationSpec.windowSpec.minHeight = 360;
  applicationSpec.windowSpec.fullscreen = FE_TRUE;
  applicationSpec.windowSpec.vSync = FE_TRUE;
  applicationSpec.windowSpec.resizeble = FE_TRUE;
  applicationSpec.windowSpec.iconPath = Path(applicationSpec.resourcesDir + "\\MyLogo.png");
  applicationSpec.windowSpec.iconSmallPath = Path(applicationSpec.resourcesDir + "\\MyLogo.png");
  applicationSpec.bootSpec = bootSpec;
  
  Force::Application* application = new Force::Application(applicationSpec);
  return application;
}

Element System

To access to engine main update loop and hold our code properly we use Elements.

Include the Force/Core/Element.h from Force::Corenamespace. Next creates new file and class ExampleElement.h somewhere in folder Elements and inherent it from Element.

Element has pack events that called in some time by application and controls by Force::ElementEngine. List of events called by application:

Element Events
Description

OnWindowCreate()

Calls when application creates platform and window, but before the OnCreate(). Prefer using this for setting custom title. Not use rendering, audio, physics, scripting code here because contexts of it was not created at this point.

OnGuiCreate()

Calls during Dear's ImGui Context creation. This function will not execute if application disable support ImGui. Main usage of this function is customize the ImGui global settings during creation for each application.

OnCreate()

Calls when all application engines was initialized. Difference with OnPostCreate(), that this function calls before showing window.

OnPostCreate()

Calls after OnCreate(). This same as OnCreate() but after showing window.

OnUpdate()

Calls by application in engine main update loop every frame, with passing the delta time variable.

OnEvent()

Calls by application when any event inherited from Event is invokes.

OnRenderGui()

Calls after main rendering, when Dear's ImGui begin their rendering frame. This function was not be called if application disable support of Dear's ImGui.

OnDestroy()

Calls when application exiting from main engine update loop.

Rendering using Elements

This example will implement Element as basic test for Force Renderer.

#pragma once

#include "Force/Core/Element.h"
#include "Force/Math/Transform.h"
#include "Force/SceneManagment/SceneCamera.h"

using namespace Force;
using namespace Force::Core;
using namespace Force::Graphics;
using namespace Force::SceneManagment;

class ExampleElement : public Element {
private:
	RuntimeCamera    camera;
	Transform        cameraTransform;
	float            rotationZ;
public:
	ExampleElement();
public:
	void OnCreate() override;
	void OnUpdate(Delta delta) override;
	void OnDestroy() override;
};

Next create the implementation file ExampleElement.cpp, and include ExampleElement.h.

#include "Elements/ExampleElement.h"
#include "Force/Graphics/RenderCmd.h"
#include "Force/Graphics/RenderEngine2D.h"
#include "Force/Graphics/Texture2D.h"

Ref<Texture2D> texture;
ExampleElement::ExampleElement() : Element("Example", ElementCategory_User) {}

void ExampleElement::OnCreate() {

	// Setup up camera.
	camera.SetProjectionMatrixType(CameraProjectionType::Perspective);
	cameraTransform.SetLocalTranslation({ 0.0f, 0.0f, 5.0f });

	// Loading the texture.
	texture = Texture2D::Create("Resources/IconBuild.png");
}

void ExampleElement::OnUpdate(Delta delta) {

	// Clearing the screen.
	RenderCmd::ClearDepthStencil(ClearBit_DepthBuffer | ClearBit_ColorBuffer);
	RenderCmd::ClearColor(Vector4f{ 0.4f, 0.4f, 0.4f, 1.0f });

	// Render primitives.
	Matrix4f view = cameraTransform.GetViewMatrix();
	RenderEngine2D::Begin(camera, view);
	RenderEngine2D::RenderRect(Rect(0.0f, 0.0f), { 1, 0, 0, 1 });
	RenderEngine2D::End();
}

void ExampleElement::OnDestroy() {
	// Free the allocated resources.
	texture.Free();
}

In OnCreate() function we setting up the perspective camera and set its Z position to be 5.0, to make our primitives visible from that camera.

camera.SetProjectionMatrixType(CameraProjectionType::Perspective);
cameraTransform.SetLocalTranslation({ 0.0f, 0.0f, 5.0f });

In OnUpdate() function we call few commands from RenderCmd from Force::Graphics to clear main screen view with new color and clear depth and color buffers.

RenderCmd::ClearDepthStencil(ClearBit_DepthBuffer | ClearBit_ColorBuffer);
RenderCmd::ClearColor(Vector4f{ 0.4f, 0.4f, 0.4f, 1.0f });

Before we can render anything we need to call Begin() and End() and pass to it camera itself and it calculated view. View matrix can be calculated from any Transform, by GetViewMatrix().

Matrix4f view = cameraTransform.GetViewMatrix();
RenderEngine2D::Begin(camera, view);
RenderEngine2D::RenderRect(Rect(0.0f, 0.0f), { 1, 0, 0, 1 });
RenderEngine2D::End();

Today Force 2D Renderer support few types of primitive:

  • Points

  • Lines

  • Rects

  • Rects Textured

  • Rects Lined

  • Circles

  • Circles Thinned

  • Sprites

  • AABB's

If you want you can add few more example primitives:

// Lines
RenderEngine2D::RenderLine({ 2.0f, 1.5f }, { -2.0f, 1.5f }, { 1, 0, 1, 1 });

// Rects
RenderEngine2D::RenderRect(Rect( -1.85f, 0.0f ), { 1, 0, 0, 1 });
RenderEngine2D::RenderRect(Rect(  1.85f, 0.0f ), { 1, 0, 0, 1 });
RenderEngine2D::RenderRectTextured(Transform({ 0.0f, 2.5f }, rotationZ ), { 1, 1, 1, 1 }, texture);

// Circles
RenderEngine2D::RenderCircle(Rect(0.0f, 0.0f), { 0, 1, 1, 1 }, 3.0f, 1.0f);

// Sprites
RenderEngine2D::RenderSprite(Transform({ 0.0f, 1.0f }), Sprite(), { 1, 1, 0, 1 });

The RenderSprite() use the ECS components, one for Transform and another for Sprite. C++ API is almost identical to C#, so you can find more information in this section.

The RenderRectTextured() accept the texture parameter. To create and load a texture use Texture2D from Force::Graphics namespace. Also its accepts Transform instead of Rect because we pass rotationZ value to have opportunity to rotate the rect.

texture = Texture2D::Create("Resources/MyTexture.png");

We have finished creating your own rendering element, now you just need to add element to application in Force::CreateApplication().

...
application->AddElement(new ExampleElement());
...
return application;

You can use two ways to do this by AddElementLast() to add element to end of container, and AddElement() to add scene to begin of container. And after that you can run your app with peace of mind.

Check Example\ExampleApplication for full example in ForceDev repository for details.

Console Applications

Force also allows to create a console applications, and cut off a lot of unnecessary API's, such a main window, rendering, assets, languages, IO, and display only console that you can write, read or test or maybe even create a server (even if Force not have this API yet.).

To create a console application all that you need to do is in you CreateApplication function set consoleApp to FE_TRUE:

...

applicationSpec.workingPath = "C:\\Force\\ConsoleApplication";
applicationSpec.resourcesDir = "Resources";
...

applicationSpec.consoleApp = FE_TRUE;

...
application->AddElement(new ConsoleElement());
...
return application;

Also you can disable debug logger that you Force and use specific release logger, that will log only your message to console. To do this set this in you config file inside ManagedInitializeCore function:

...

coreSpec.initLoggerInRelease  = FE_TRUE;   // Allow logger in release, because it console app.
coreSpec.initConsoleInRelease = FE_TRUE;   // Allow console in release for console apps.

...

Check Example\ConsoleApplication for full example in ForceDev repository for details.

Solution and project configuration

Projects and solution we can configure using Premake that written on Lua. Lua is easy to learn scripting language, with minimum dependences and code. Each premake file stores on each of project directories. Main premake file is ForceEngine.lua stored in root of ForceDev. It contains utility functions to work with projects and solution itself. For reference you can check Lua and Premake documentation.

Force Linking

In the variable LinkForce we can specify how Force wil be linked and build: "Dynamic" to ".dll" or "Static to ".lib". Force from 23 commit (993651b) of dev using Static linking and to migrate to dynamic requested rewrite hole a bunch of code.

So for now Force supports only static linking and look like this:

LinkForce = LinkingType.Static

Force Projects

Projects in Force separates by few groups: Core, Examples and Libraries and in that order displays in Visual Studio. About libraries we talk about later. Force project list available at this moment is:

Projects.Core    ["Force"]              = true
Projects.Core    ["ForceCS"]            = true
Projects.Core    ["ForceEditor"]        = true
Projects.Core    ["ForceNave"]          = true
Projects.Core    ["ForceRuntime"]       = true
Projects.Examples["ExampleApplication"] = true
Projects.Examples["ConsoleApplication"] = true

If you dont need them to exist you can just turn it off by setting to false.

Each of this project and libraries defined as Libraries has its Project Directory ProjDir relative to ForceDir. Some of this projects - libraries that stored either relative to Force/Libraries or some of them relative to vckpg/packages .

All of this libraries has BinaryDir depending on build configuration (Debug, Release) where all binaries files stored for that library, then IncludeDir where all header files stored, and Library itself thats directly points to static library (.lib) witch you can link to Projects.Core.Force library.

Force Engine Solution

The code for solution looks like this:

workspace "ForceEngine"
	architecture   "x64"
	startproject   "ForceEditor"
	configurations ("Debug","Release")
	solution_items (".editorconfig" )
	flags          ("MultiProcessorCompile")

Its basic premake script workspace with two configurations and some flags. Basically here all what you need for solution so dont recommended it to change.

Force Project

Go to Force and open Force.lua premake file. This is file that contains definition of the main project, basically all other projects are structured this way.

project "Force"
	kind          "StaticLib"
	language      "C++"
	cppdialect    "C++17"
	staticruntime "on"
	targetdir     ("%{ForceDir.Bin}/" .. BuildDir .. "/%{prj.name}/Lib")
	objdir        ("%{ForceDir.Bin}/" .. BuildDir .. "/%{prj.name}/Obj")
	pchheader     "ForcePCH.h"
	pchsource     "Sources/ForcePCH.cpp"
	
	-- Files to include
	files { ... }
	
	-- Directories to include
	includedirs { ... }
	
	-- Links and defines
	links   (GetLinkedLibraries("Any"))
	defines (GetLinkedLibrariesDefines())

	-- Windows specific
	filter "system:windows"
		systemversion "latest"
		defines (GetWindowsDefines())
		files { ... }
	
	-- Linux specific
	filter "system:linux"
		systemversion "latest"
		defines (GetLinuxDefines())
		files { ... }
	
	-- Debug only
	filter "configurations:Debug"
		runtime "Debug"
		symbols "on"
		links   (GetLinkedLibraries("Debug"))
		defines (GetConfigurationDefines("Debug"))
		
	-- Release only
	filter "configurations:Release"
		runtime  "Release"
		optimize "on"
		links    (GetLinkedLibraries("Release"))
		defines  (GetConfigurationDefines("Release"))
	

The most important here is targetdir and objdir where project will store when build project. By default it will be Bin/*BuildDir/*ProjectName/Lib and Bin/*BuildDir/*ProjectName/Obj

Then goes files and include directories (includedir) witch project will be included and use, and links list and already configured for each library of libraries that will be linked to Force.

Defines (defines) that contains list of predefined FE_LIBRARY_* macross and other platform libraries.

And the goes that same for each platform and configuration.

Application and Libraries

Enable and disable libraries

When you write applications, you can disable some libraries and especially its linking if you dont use them to decrease size of the your executable. Now it totally achievable. To do that please go to ForceEngine.lua and find libraries list:

Libraries = {}
Libraries["Vulkan"]       = false
Libraries["DirectX12"]    = false
Libraries["Mono"]         = true
Libraries["Curl"]         = true
Libraries["LibSndFile"]   = true
Libraries["OpenAL"]       = true
Libraries["Assimp"]       = true
Libraries["OpenGL"]       = true
Libraries["Glm"]          = true
Libraries["Glfw"]         = true
Libraries["DxErr"]        = true
Libraries["DxTK"]         = true
Libraries["Yaml"]         = true
Libraries["HwInfo"]       = true
Libraries["Box2D"]        = true
Libraries["MsdfAtlasGen"] = true
Libraries["MsdfGen"]      = true
Libraries["FreeType"]     = true
Libraries["Stb"]          = true
Libraries["EnTT"]         = true
Libraries["ImGui"]        = true
Libraries["ImGuizmo"]     = true
Libraries["LibZip"]       = true
Libraries["SpdLog"]       = true

Just set you library to false and you ready to go. Its disable library linking for static libraries, for dynamic libraries its disable copying its .dll file in to executable directory, and sets it proper macros FE_LIBRARY_XXX to 0. After this you need to fully rebuild the solution for Debug and Release configuration.

Libraries that now can be disables:

OpenGL
Vulkan
DirectX12
Glfw
Mono
LibSndFile (including):
 - flac
 - mpg123
 - mp3lame
 - ogg
 - opus
Assimp (including):
 - zlib
 - minizip
 - pugixml  

For other libraries its not tested, and basically other libraries its tiny and all static linked so you dont have any .dll file requested and dont need to disable.

Missing Mono .NET Framework

When you linked Mono and Mono Runtime in to Force you can not have Mono folder with all Runtime .Net Framework. If that happens means you forgot copy proper version of you .Net Framework from MonoSDK. To do that please go to C:\_YourMonoSDKPath_\lib\mono and select you version of .NET Framework and copy it Mono folder to you working or executable directory or just download this archive.

Last updated