Ares is a simple, extensible game engine designed to eventually support both 2D and 3D game development. Currently, Ares supports rendering ImGui elements, window management with customizable startup options, and an event system. The engine is designed to grow with your project and will eventually include full 2D and 3D rendering capabilities.
- Introduction
- Table of Contents
- Key Features
- Installation
- Creating a New Blank Project
- Usage
- License
- Contact
- ImGui Rendering: Currently supports rendering ImGui UI elements.
- Window Management: Allows for window style customization:
- Windowed, Borderless, Fullscreen, Fullscreen Exclusive (changes resolution)
- Resizable and maximized windows.
- Event System: Supports event handling with custom layers and user-defined event functions.
- Logging: Built-in logging with various severity levels (trace, info, warn, error, critical).
- Extensibility: Easily add layers to manage different parts of your game or application.
- Premake 5: You’ll need Premake 5 to generate project files.
- Git: To clone the repository.
git clone --recursive https://github.com/yourusername/ares.git
cd ares
-
Download and install Premake 5 if you haven't already.
-
Place premake5.exe inside the
/scripts
folder. -
In the scripts directory of the cloned repository, open a terminal and run Premake to generate project files for your development environment:
premake5 --file=..\premake5.lua <your_environment>
Replace
<your_environment>
with your desired build system, such asvs2022
for Visual Studio 2022 orgmake
for GNU Make. -
Open the generated project in your IDE and build the solution.
The current premake5.lua
is set up with the internal project named Sandbox. If you'd like to create a new blank project, such as MyApplication, follow these steps:
-
Make sure you have downloaded Premake 5 and placed
premake5.exe
inside the/scripts
folder. -
Run the
InitializeProjet.bat
script.- First, it will ask you what you want to name your project. In the current
premake5.lua
file it is Ares. - Then, it will ask you what you want the internal name of your project to be. In the current
premake5.lua
file it is Sandbox. - Using these, the script will create a
premake5.lua
just for you, overwriting the one cloned from the repo. The only things that are different are the names. - The script will then ask if you want it to generate a script for running Premake. If yes, it will create
GenerateProjectFiles.bat
in the/scripts
folder. - Finally, the script will ask you if you would like to run the generated script to create your project files.
- First, it will ask you what you want to name your project. In the current
-
With your project files generated, you are ready to start working on your blank project!
-
Please see Create a New Application to learn the basics.
In your blank project, create a new file. For our example, it will be MyApplication.cpp
. In MyApplication.cpp
include Ares and the necessary entry point:
// MyApplication.cpp
#include <Ares.h>
#include <Engine/Core/EntryPoint.h>
class MyApplication : public Ares::Application
{
public:
MyApplication()
{
// Constructor code
}
~MyApplication()
{
// Destructor code
}
};
Ares::Application* Ares::CreateApplication()
{
// Set startup settings here before
// before returning MyApplication()!
return new MyApplication();
}
You can customize the startup window style with macros:
Ares::ApplicationSettings settings;
settings.WindowStyle = AR_WINDOW_DEFAULT_WINDOW;
return new MyApplication(settings);
MyApplication.cpp complete code.
// MyApplication.cpp
#include <Ares.h>
#include <Engine/Core/EntryPoint.h>
class MyApplication : public Ares::Application
{
public:
MyApplication(const Ares::ApplicationSettings& settings)
: Application(settings)
{
// Constructor code
}
~MyApplication()
{
// Destructor code
}
};
Ares::Application* Ares::CreateApplication()
{
Ares::ApplicationSettings settings;
settings.WindowStyle = AR_WINDOW_DEFAULT_WINDOW;
return new MyApplication(settings);
}
Here’s a list of available window styles:
Value | Description |
---|---|
AR_WINDOW_WINDOWED Ares::WindowSettings::Windowed |
A standard window with a title bar and borders. |
AR_WINDOW_BORDERLESS Ares::WindowSettings::Borderless |
A window without borders or a title bar, often used for fullscreen-like experiences but within a window. The user cannot resize or move the window. |
AR_WINDOW_FULLSCREEN Ares::WindowSettings::Fullscreen |
A window that covers the entire screen without borders. This style is often used for immersive fullscreen applications while still allowing the user to switch to other applications. |
AR_WINDOW_FULLSCREEN_EX Ares::WindowSettings::FullscreenExclusive |
A fullscreen window that takes exclusive control of the screen, changing the screen resolution. Unlike the standard fullscreen, this style can provide better performance by bypassing some windowing system overhead. |
AR_WINDOW_RESIZABLE Ares::WindowSettings::Resizable |
Allows a AR_WINDOW_WINDOWED to be resized. |
AR_WINDOW_MAXIMIZED Ares::WindowSettings::Maximized |
A window that starts in a maximized state. If the AR_WINDOW_BORDERLESS flag is set, then this will make the window fullscreen. |
AR_WINDOW_DEFAULT_WINDOW Ares::WindowSettings::DefaultWindow |
A combination of AR_WINDOW_WINDOWED and AR_WINDOW_RESIZABLE . The default window style. This style is used when no specific window settings are provided or when set to 0. |
AR_WINDOW_FULLSCREEN_BORDERLESS Ares::WindowSettings::FullscreenBorderless |
A combination of AR_WINDOW_BORDERLESS and AR_WINDOW_FULLSCREEN , where the window is fullscreen without borders but still behaves like a normal window in terms of interaction with the operating system. |
AR_WINDOW_FULLSCREEN_WINDOWED Ares::WindowSettings::FullscreenWindowed |
A combination of AR_WINDOW_WINDOWED and AR_WINDOW_MAXIMIZED , where the window is maximized to cover most of the screen but retains the windowed nature with the ability to move but not resize. |
Create a file MyLayer.h
with a new class that inherits from Ares::Layer
:
// MyLayer.h
#pragma once
#include <Ares.h>
class MyLayer : public Ares::Layer
{
public:
MyLayer();
virtual ~MyLayer() = default;
virtual void OnAttach() override;
virtual void OnDetach() override;
void OnUpdate(Ares::Timestep ts) override;
void OnEvent(Ares::Event& e) override;
virtual void OnImGuiRender() override;
};
MyLayer.cpp complete code.
// MyLayer.cpp
#include "MyLayer.h"
MyLayer::MyLayer()
: Layer("MyLayer")
{
}
void MyLayer::OnAttach()
{
}
void MyLayer::OnDetach()
{
}
void MyLayer::OnUpdate(Ares::Timestep ts)
{
}
void MyLayer::OnEvent(Ares::Event& e)
{
}
void MyLayer::OnImGuiRender()
{
}
In MyApplication.cpp
, push the layer:
// MyApplication.cpp
MyApplication::MyApplication(const Ares::ApplicationSettings& settings)
: Application(settings)
{
PushLayer(new MyLayer());
}
MyApplication.cpp complete code.
// MyApplication.cpp
#include <Ares.h>
#include <Engine/Core/EntryPoint.h>
#include "MyLayer.h"
class MyApplication : public Ares::Application
{
public:
MyApplication(const Ares::ApplicationSettings& settings)
: Application(settings)
{
// Constructor code
PushLayer(new MyLayer());
}
~MyApplication()
{
// Destructor code
}
};
Ares::Application* Ares::CreateApplication()
{
Ares::ApplicationSettings settings;
settings.WindowStyle = AR_WINDOW_DEFAULT_WINDOW;
return new MyApplication(settings);
}
Inside your layer, you can handle specific events, such as a key press:
// MyLayer.cpp
void MyLayer::OnEvent(Ares::Event& e)
{
Ares::EventDispatcher dispatcher(e);
dispatcher.Dispatch<Ares::KeyPressedEvent>(AR_BIND_EVENT_FN(MyLayer::OnKeyPressed));
}
bool MyLayer::OnKeyPressed(Ares::KeyPressedEvent& e)
{
if (e.GetKeyCode() == Ares::KeyCode::Space)
{
// Code for Space key
}
return false;
}
MyLayer.h complete code.
// MyLayer.h
#pragma once
#include <Ares.h>
class MyLayer : public Ares::Layer
{
public:
MyLayer();
virtual ~MyLayer() = default;
virtual void OnAttach() override;
virtual void OnDetach() override;
void OnUpdate(Ares::Timestep ts) override;
void OnEvent(Ares::Event& e) override;
virtual void OnImGuiRender() override;
private:
bool OnKeyPressed(Ares::KeyPressedEvent& e);
};
MyLayer.cpp complete code.
// MyLayer.cpp
#include "MyLayer.h"
MyLayer::MyLayer()
: Layer("MyLayer")
{
}
void MyLayer::OnAttach()
{
}
void MyLayer::OnDetach()
{
}
void MyLayer::OnUpdate(Ares::Timestep ts)
{
}
void MyLayer::OnEvent(Ares::Event& e)
{
Ares::EventDispatcher dispatcher(e);
dispatcher.Dispatch<Ares::KeyPressedEvent>(AR_BIND_EVENT_FN(MyLayer::OnKeyPressed));
}
void MyLayer::OnImGuiRender()
{
}
bool MyLayer::OnKeyPressed(Ares::KeyPressedEvent& e)
{
if (e.GetKeyCode() == AR_KEY_SPACE)
{
// Code for Space key
}
return false;
}
Ares includes robust logging functionality to help developers track application behavior and debug efficiently. Logging in Ares is accessed through a set of predefined macros that support various log levels. These macros are simple to use and accept inputs in a format compatible with the fmt library, allowing for powerful and flexible message formatting.
Available Logging Macros:
Macro | Definition |
---|---|
AR_TRACE |
For detailed information, typically used during development to trace program execution. |
AR_BUG |
Used for debugging. |
AR_INFO |
For general informational messages that highlight the progress of the application. |
AR_WARN |
For warning messages that indicate potentially harmful situations. |
AR_ERROR |
For error messages that indicate a significant problem, though the application can continue running. |
AR_CRITICAL |
For critical issues that likely require immediate attention or cause the application to terminate. |
Example Usage
int someValue = 42;
std::string someString = "Ares Engine";
// Log a trace message with formatted values
AR_TRACE("SomeValue: {} - Message: {}", someValue, someString);
// Log an error
AR_ERROR("An error occurred with value: {}", someValue);
In the example above:
{}
placeholders are replaced with the corresponding variables, just as with thefmt
library.- This approach ensures that logging macros are flexible, concise, and easy to read.
Console or Windowed Application:
Logging messages are displayed differently based on how the application is configured:
- Console Applications: Logs are printed directly to the console window, providing immediate visibility.
- Windowed Applications: Logs can be rendered to an ImGui-based console, allowing developers to view logs just as easily as with a Console Application.
Integrating the ImGui Console:
To enable logging in a Windowed Application, add the following code to the OnImGuiRender()
method in MyLayer.cpp
.
// MyLayer.cpp
void MyLayer::OnImGuiRender()
{
Ares::Log::GetConsole()->Draw("Console", true);
}
This creates an ImGui window named "Console"
where all log messages are displayed.
Advanced Use Case:
You can also add logic to toggle the visibility of the ImGui console. For example:
- Add a member variable to track visibility:
// MyLayer.h
...
private:
bool m_ShowConsole;
...
- Toggle its state with a key press (e.g., the grave accent key "`"):
// MyLayer.cpp
bool MyLayer::OnKeyPressed(Ares::KeyPressedEvent& e)
{
if (e.GetKeyCode() == Ares::KeyCode::GraveAccent)
{
m_ShowConsole = !m_ShowConsole;
}
return false;
}
- Use the variable to conditionally render the console:
// MyLayer.cpp
void MyLayer::OnImGuiRender()
{
Ares::Log::GetConsole()->Draw("Console", m_ShowConsole);
}
By incorporating logging into your application, you can efficiently monitor runtime behavior, debug issues, and gain insight into the engine's internal operations.
MyLayer.h complete code.
// MyLayer.h
#pragma once
#include <Ares.h>
class MyLayer : public Ares::Layer
{
public:
MyLayer();
virtual ~MyLayer() = default;
virtual void OnAttach() override;
virtual void OnDetach() override;
void OnUpdate(Ares::Timestep ts) override;
void OnEvent(Ares::Event& e) override;
virtual void OnImGuiRender() override;
private:
bool OnKeyPressed(Ares::KeyPressedEvent& e);
bool m_ShowConsole;
};
MyLayer.cpp complete code.
// MyLayer.cpp
#include "MyLayer.h"
MyLayer::MyLayer()
: Layer("MyLayer"), m_ShowConsole(false)
{
int someValue = 42;
std::string someString = "Ares Engine";
// Log a trace message with formatted values
AR_TRACE("SomeValue: {} - Message: {}", someValue, someString);
// Log an error
AR_ERROR("An error occurred with value: {}", someValue);
}
void MyLayer::OnAttach()
{
}
void MyLayer::OnDetach()
{
}
void MyLayer::OnUpdate(Ares::Timestep ts)
{
}
void MyLayer::OnEvent(Ares::Event& e)
{
Ares::EventDispatcher dispatcher(e);
dispatcher.Dispatch<Ares::KeyPressedEvent>(AR_BIND_EVENT_FN(MyLayer::OnKeyPressed));
}
void MyLayer::OnImGuiRender()
{
Ares::Log::GetConsole()->Draw("Console", m_ShowConsole);
}
bool MyLayer::OnKeyPressed(Ares::KeyPressedEvent& e)
{
if (e.GetKeyCode() == Ares::KeyCode::GraveAccent)
{
m_ShowConsole = !m_ShowConsole;
}
return false;
}
Ares currently includes basic rendering functionality. While it's still in the early stages, these features lay the groundwork for more advanced rendering capabilities to be added in the future.
Current Features:
Ares::RenderCommand::SetClearColor
: Sets the clear color for the OpenGL viewport. You can specify a color using an RGBA vector, like so:
Ares::RenderCommand::SetClearColor({ 0.1f, 0.1f, 0.1f, 1.0f });
Ares::RenderCommand::Clear
: Clears the OpenGL viewport buffers.
Ares::RenderCommand::Clear();
These commands can be used in your layer's OnUpdate()
function to define the background color and refresh the viewport each frame.
Example Usage:
void MyLayer::OnUpdate(Ares::Timestep ts)
{
Ares::RenderCommand::SetClearColor({ 0.1f, 0.1f, 0.1f, 1.0f });
Ares::RenderCommand::Clear();
}
This may not seem like much yet, but these functions are just the beginning. The rendering system will continue to expand to include features for rendering 2D and 3D objects, lighting, shaders, and more. Stay tuned for future updates!
MyApplication.cpp
// MyApplication.cpp
#include <Ares.h>
#include <Engine/Core/EntryPoint.h>
#include "MyLayer.h"
class MyApplication : public Ares::Application
{
public:
MyApplication(const Ares::ApplicationSettings& settings)
: Application(settings)
{
// Constructor code
PushLayer(new MyLayer());
}
~MyApplication()
{
// Destructor code
}
};
Ares::Application* Ares::CreateApplication()
{
Ares::ApplicationSettings settings;
settings.WindowStyle = AR_WINDOW_DEFAULT_WINDOW;
return new MyApplication(settings);
}
MyLayer.h
// MyLayer.h
#pragma once
#include <Ares.h>
class MyLayer : public Ares::Layer
{
public:
MyLayer();
virtual ~MyLayer() = default;
virtual void OnAttach() override;
virtual void OnDetach() override;
void OnUpdate(Ares::Timestep ts) override;
void OnEvent(Ares::Event& e) override;
virtual void OnImGuiRender() override;
private:
bool OnKeyPressed(Ares::KeyPressedEvent& e);
bool m_ShowConsole;
};
MyLayer.cpp
// MyLayer.cpp
#include "MyLayer.h"
MyLayer::MyLayer()
: Layer("MyLayer"), m_ShowConsole(false)
{
int someValue = 42;
std::string someString = "Ares Engine";
// Log a trace message with formatted values
AR_TRACE("SomeValue: {} - Message: {}", someValue, someString);
// Log an error
AR_ERROR("An error occurred with value: {}", someValue);
}
void MyLayer::OnAttach()
{
}
void MyLayer::OnDetach()
{
}
void MyLayer::OnUpdate(Ares::Timestep ts)
{
Ares::RenderCommand::SetClearColor({ 0.1f, 0.1f, 0.1f, 1.0f });
Ares::RenderCommand::Clear();
}
void MyLayer::OnEvent(Ares::Event& e)
{
Ares::EventDispatcher dispatcher(e);
dispatcher.Dispatch<Ares::KeyPressedEvent>(AR_BIND_EVENT_FN(MyLayer::OnKeyPressed));
}
void MyLayer::OnImGuiRender()
{
Ares::Log::GetConsole()->Draw("Console", m_ShowConsole);
}
bool MyLayer::OnKeyPressed(Ares::KeyPressedEvent& e)
{
if (e.GetKeyCode() == Ares::KeyCode::GraveAccent)
{
m_ShowConsole = !m_ShowConsole;
}
}
This project is licensed under the MIT License.
For issues or feature requests, please create a new issue on the GitHub repository.