Version 5 vs 30
Version 5 vs 30
Edits
Edits
- Edit by 0xseantasker, Version 30
- Nov 24 2021 10:09 AM
- Edit by 0xseantasker, Version 5
- Oct 17 2014 9:46 PM
- ·Vertex colouring is disabled by default now.
Edit Older Version 5... | Edit Current Version 30... |
Content Changes
Content Changes
Echo provides the components you need to write an application that can be built without modification on multiple platforms. An application is based around creating at least one Kernel object and executing it. How a Kernel is executed depends on the platform your application will run on, because of this your application does not have an entry point, such as `main()`, that you would be familiar with.
Instead, the equivalent of your main entry point file would contain a method EchoInitialise() which should return a smart pointer to a Kernel object. You will need to create a Kernel object or an instance of a class that inherits from Kernel and return it. If your application is going to have multimedia functionality, such as a game, then you may like to use the Application class. The following is a simple example:
```
class MyApplication : public Application
{
public:
MyApplication() : mTask("MyTask")
{
//Application inherits from Kernel. If the Kernel doesn't have any tasks to process then it will not
//continue the program loop which is why we give it a Task to process even though the Task
//does not do anything.
AddTask(mTask);
}
private:
Task mTask;
};
shared_ptr<Kernel> EchoInitialise()
{
//Create an instance of MyApplication, initialise it and return.
shared_ptr<Application> application(new MyApplication());
if(application->Initialise("ApplicationTest", 800,600,false))
{
return application;
}
//Failure to initialise an Application object will occur if the target platform has an incomplete configuration.
return shared_ptr<Kernel>();
}
```
This is a simple example to show how you could use Echo for rendering.
```
int main(int argc, char** argv)
{
Kernel kernel;
shared_ptr<RenderTarget> target = Platform::CreateRenderTarget("Window",kernel,800,300,32,false);
MultiRenderer renderer(target);
Scene scene;
shared_ptr<Camera> camera = scene.CreateCamera();
camera->SetPosition(-1,10,10);
camera->LookAt(0,0,0);
shared_ptr<Camera> camera2 = scene.CreateCamera();
camera2->SetPosition(1,10,10);
camera2->LookAt(0,0,0);
renderer.CreateRenderer(make_shared<Viewport>(0,0,0.5,1),camera);
renderer.CreateRenderer(make_shared<Viewport>(0.5,0,1,1),camera2);
kernel.AddTask(renderer);
kernel.Execute(Platform::CreateExecutionModel());
return 0;
}
```
In this example we use a custom scene renderable object that renders a cube mesh. The cube is created manually rather than loading a file to keep this example simple (i.e. not use resources). This example renders the cube through two different viewports using a Multi-Renderer.
```
//Platform and Kernel includes
#include <echo/Platform.h>
#include <echo/Kernel/Kernel.h>
//Rendering includes
#include <echo/Graphics/Renderer.h>
#include <echo/Graphics/MultiRenderer.h>
#include <echo/Graphics/Scene.h>
#include <echo/Graphics/Camera.h>
#include <echo/Graphics/Viewport.h>
#include <echo/Graphics/SceneRenderable.h>
//Graphics object includes
#include <echo/Graphics/Mesh.h>
#include <echo/Graphics/SubMesh.h>
//To make this example a little easier on the eyes.
using namespace Echo;
//A basic custom scene renderable.
class SpinningCube : public SceneRenderable
{
public:
SpinningCube() : mAngle(0)
{
//Create a cube
shared_ptr<SubMesh> subMesh = mMesh.CreateSubMesh();
subMesh->AddVertex(Vector3(-2,2,-2));
subMesh->AddColour(Colour(1,0,0));
subMesh->AddVertex(Vector3(2,2,-2));
subMesh->AddColour(Colour(0,1,0));
subMesh->AddVertex(Vector3(-2,-2,-2));
subMesh->AddColour(Colour(0,0,1));
subMesh->AddVertex(Vector3(2,-2,-2));
subMesh->AddColour(Colour(1,1,0));
subMesh->AddVertex(Vector3(-2,2,2));
subMesh->AddColour(Colour(1,1,0));
subMesh->AddVertex(Vector3(2,2,2));
subMesh->AddColour(Colour(0,0,1));
subMesh->AddVertex(Vector3(-2,-2,2));
subMesh->AddColour(Colour(0,1,0));
subMesh->AddVertex(Vector3(2,-2,2));
subMesh->AddColour(Colour(1,0,0));
subMesh->AddFace(IndexedTriangle(0,1,2));
subMesh->AddFace(IndexedTriangle(2,1,3));
subMesh->AddFace(IndexedTriangle(5,4,6));
subMesh->AddFace(IndexedTriangle(5,6,7));
subMesh->AddFace(IndexedTriangle(4,0,6));
subMesh->AddFace(IndexedTriangle(6,0,2));
subMesh->AddFace(IndexedTriangle(0,4,5));
subMesh->AddFace(IndexedTriangle(0,5,1));
subMesh->AddFace(IndexedTriangle(1,5,3));
subMesh->AddFace(IndexedTriangle(3,5,7));
subMesh->AddFace(IndexedTriangle(2,3,7));
subMesh->AddFace(IndexedTriangle(2,7,6));
mMesh.CalculateAABB();
//Create a basic material for the cube
shared_ptr<Material> material(new Material());
RenderPass pass;
pass.SetCullMode(RenderPass::CullModes::BACK);
pass.SetVertexColouringEnabled(true);
material->AddPass(pass);
//Set the mesh material
mMesh.SetMaterial(material);
}
AxisAlignedBox GetLocalAxisAlignedBox()
{
AxisAlignedBox box;
box.setMinimum(mMesh.GetMin());
box.setMaximum(mMesh.GetMax());
return box;
}
void Render(const Matrix4& transform, RenderTarget& renderTarget)
{
SetOrientation(Quaternion(Radian(mAngle),Vector3(0.4,0.5,1)));
mAngle+=0.1f;
mMesh.Render(transform * GetTransform(),renderTarget);
}
private:
Mesh mMesh;
f32 mAngle;
};
int main(int argc, const char* args[])
{
//You don't have to use a kernel object if you want to manage frame updates yourself.
Kernel kernel;
kernel.SetExecutionModel(Platform::CreateExecutionModel());
//Create a render window
shared_ptr<RenderTarget> target = Platform::CreateRenderTarget("Window",kernel,800,300,32,false);
// Renderers are used to render a camera (which renders a scene) in a viewport on a render target. They act as simple mapping
// objects and perform screen clearing and buffer swapping.
//
// A multirenderer will render multiple Renderer objects and control the screen clearing and buffer swapping (otherwise you would
// need to configure each Renderer yourself (which is entirely possible).
MultiRenderer renderer(target);
// Create a scene with a camera.
Scene scene;
shared_ptr<Camera> camera = scene.CreateCamera();
camera->SetPosition(0,0,10);
// Create two renderers taking half of the screen each.
renderer.CreateRenderer(make_shared<Viewport>(0,0,0.5,1),camera);
renderer.CreateRenderer(make_shared<Viewport>(0.5,0,1,1),camera);
// Add our multi-renderer as a task to the Kernel. The Renderer's Update() method will render the
// screen so you may need to set the priority of the task so it updates last.
kernel.AddTask(renderer);
// Create a spinning cube object, defined above.
shared_ptr< SpinningCube > spinningCube(new SpinningCube());
scene.AddRenderable(spinningCube);
// Start program loop
kernel.Execute();
return 0;
}
```
Please either [[projects/echo_3/installing/|install]] or [[projects/echo_3/building/|build and install Echo]].
=Your first project=
Now that you have everything installed, create a new project:
1. Open a command prompt and run the GenerateProject script
```
$ECHO_ENGINE_INSTALL_DIR/templates/cmake/GenerateProject.sh MyEchoProject EchoApplicationProject destinationFolder
```
You can run the script without any parameters and it will include a list of available templates.
NOTE: If `ECHO_ENGINE_INSTALL_DIR` is not set (it does not have to be) and you're not sure where to find Echo, try `/opt/echo3` which is the default install location.
2. The output will display the path to the new project folder and build simple instructions, however the `cmake` templates also include some helper scripts to config, build, and run the projects for specified platforms. Since Echo is designed to be cross platform we want to make targeting other platforms simple, so we recommend using these steps. To learn how you should configure your IDE you can inspect the scripts (and follow the rabbit hole) to learn the few things that need to be done.
```
./cmakeplatform linux
./buildplatform linux
```
3. To run the project run from the project directory (rather than the build directory). This is because the template references resources relative to the project folder. You can change the configuration however you like though.
```
./runplatform linux
```
The Echo Application template has a simple menu and main game state that you can switch between using the on screen buttons. The game state scene is made up of a spinning cube and some lights.
{F4377 size=full}
Congratulations, you have created, built and run your first Echo project!
=What next?=
Have a look at the project source code. The source files contain documentation about some Echo fundamentals and details the project Task structure.
Here are some suggestions for moving forward:
- Familiarise yourself with `Scene` objects:
-- Modify the scene.
-- Add another `SceneEntity` to the scene, give it a `Sphere` mesh (hint: the `Mesh` class contains some helper methods for generating certain meshes).
- Familiarise yourself with `Camera`s, `Renderer`s and `Viewport`s:
-- Modify the Game state to include a third `Viewport`.
- Familiarise yourself with GUI scripts:
-- In the resources folder you'll find a folder named Menu that contains various `.gui` files. These define GUI layouts of images, buttons, text etc. The element types correspond to Echo GUI classes. Play around with the menu elements.
-- Try creating a couple of new buttons to click on in the Game state to speed up or slow down the spinning cube. You will need to create a function to change the speed and set up a new binding to make it available for GUI buttons (see the application file on how to set up bindings, but set the bindings up in `Game.cpp` using the provided `FunctionBinder`).
- Familiarise yourself with `Task`s: Create a custom `Task` to periodically toggle the visibility of the sphere (or, if you didn't create one, the cube).
If you're happy with your progress so far, you can move onto a more advanced project by creating a third person game using the provided project template. The third person game template is a little more complicated that the simple application. It provides examples of:
- Using a `ContextSwitcher` to manage application states.
- How you can get values from a `Configuration` object,
- Creating a custom `Camera` controller task to follow a character
- How to create and use `MappedInputDevice`s
- How to create a generic game entity class that has discrete states defined by animations, physics bodies
- How to create a `BulletPhysicsWorld` and add `PhysicsBody` instances to it.
Echo provides the components you need to write an application that can be built without modification on multiple platforms. An application is based around creating at least one Kernel object and executing it. How a Kernel is executed depends on the platform your application will run on, because of this your application does not have an entry point, such as `main()`, that you would be familiar withPlease either [[projects/echo_3/installing/|install]] or [[projects/echo_3/building/|build and install Echo]].
Instead, the equivalent of your main entry point file would contain a method EchoInitialise() which should return a smart pointer to a Kernel object. You will need to create a Kernel object or an instance of a class that inherits from Kernel and return it. If your application is going to have multimedia functionality, such as a game, then you may like to use the Application class. The following is a simple example:
```
class MyApplication : public Application
{
public:
MyApplication() : mTask("MyTask")
{
//Application inherits from Kernel. If the Kernel doesn't have any tasks to process then it will not
//continue the program loop which is why we give it a Task to process even though the Task
//does not do anything.
AddTask(mTask);
}
private:
Task mTask;
};
shared_ptr<Kernel> EchoInitialise()=Your first project=
{
//Create an instance of MyApplication, initialise it and return.
shared_ptr<Application> application(new MyApplication());
if(application->Initialise("ApplicationTest"Now that you have everything installed, 800,600,false))
{
return application;
}
//Failure to initialise an Application object will occur if the target platform has an incomplete configuration.
return shared_ptr<Kernel>();
}
```create a new project:
This is a simple example to show how you could use Echo for rendering.1. Open a command prompt and run the GenerateProject script
```
int main(int argc, char** argv)
{
Kernel kernel;
shared_ptr<RenderTarget> target = Platform::CreateRenderTarget("Window",kernel,800,300,32,false);
MultiRenderer renderer(target);
Scene scene;
shared_ptr<Camera> camera = scene.CreateCamera();
camera->SetPosition(-1,10,10);$ECHO_ENGINE_INSTALL_DIR/templates/cmake/GenerateProject.sh MyEchoProject EchoApplicationProject destinationFolder
camera->LookAt(0,0,0);
shared_ptr<Camera> camera2 = scene.CreateCamera();```
camera2->SetPosition(1,10,10);You can run the script without any parameters and it will include a list of available templates.
camera2->LookAt(0,0,0);NOTE: If `ECHO_ENGINE_INSTALL_DIR` is not set (it does not have to be) and you're not sure where to find Echo, try `/opt/echo3` which is the default install location.
renderer.CreateRenderer(make_shared<Viewport>(0,0,0.5,1),camera);
renderer.CreateRenderer(make_shared<Viewport>(0.5,0,1,1),camera2);2. The output will display the path to the new project folder and build simple instructions, however the `cmake` templates also include some helper scripts to config, build, and run the projects for specified platforms. Since Echo is designed to be cross platform we want to make targeting other platforms simple, so we recommend using these steps. To learn how you should configure your IDE you can inspect the scripts (and follow the rabbit hole) to learn the few things that need to be done.
kernel.AddTask(renderer);
kernel.Execute(Platform::CreateExecutionModel());```
return 0;./cmakeplatform linux
}./buildplatform linux
```
In this example we use a custom scene renderable object that renders a cube mesh3. The cube is created manually rather than loading a file to keep this example simple (i.eTo run the project run from the project directory (rather than the build directory). not useThis is because the template references resources) relative to the project folder. This example rendersYou can change the cube through two different viewports using a Multi-Rendereronfiguration however you like though.
```
//Platform and Kernel includes
#include <echo/Platform.h>
#include <echo/Kernel/Kernel.h>
//Rendering includes
#include <echo/Graphics/Renderer.h>
#include <echo/Graphics/MultiRenderer.h>
#include <echo/Graphics/Scene.h>
#include <echo/Graphics/Camera.h>
#include <echo/Graphics/Viewport.h>
#include <echo/Graphics/SceneRenderable.h>
//Graphics object includes
#include <echo/Graphics/Mesh.h>
#include <echo/Graphics/SubMesh.h>
//To make this example a little easier on the eyes.
using namespace Echo;
//A basic custom scene renderable.
class SpinningCube : public SceneRenderable
{
public:
SpinningCube() : mAngle(0)
{
//Create a cube
shared_ptr<SubMesh> subMesh = mMesh.CreateSubMesh();
subMesh->AddVertex(Vector3(-2,2,-2));
subMesh->AddColour(Colour(1,0,0));
subMesh->AddVertex(Vector3(2,2,-2));./runplatform linux
subMesh->AddColour(Colour(0,1,0));
subMesh->AddVertex(Vector3(-2,-2,-2));
subMesh->AddColour(Colour(0,0,1));
subMesh->AddVertex(Vector3(2,-2,-2));
subMesh->AddColour(Colour(1,1,0));
subMesh->AddVertex(Vector3(-2,2,2));
subMesh->AddColour(Colour(1,1,0));
subMesh->AddVertex(Vector3(2,2,2));
subMesh->AddColour(Colour(0,0,1));
subMesh->AddVertex(Vector3(-2,-2,2));
subMesh->AddColour(Colour(0,1,0));
subMesh->AddVertex(Vector3(2,-2,2));
subMesh->AddColour(Colour(1,0,0));
subMesh->AddFace(IndexedTriangle(0,1,2));
subMesh->AddFace(IndexedTriangle(2,1,3));
subMesh->AddFace(IndexedTriangle(5,4,6));
subMesh->AddFace(IndexedTriangle(5,6,7));```
subMesh->AddFace(IndexedTriangle(4,0,6));
subMesh->AddFace(IndexedTriangle(6,0,2));The Echo Application template has a simple menu and main game state that you can switch between using the on screen buttons. The game state scene is made up of a spinning cube and some lights.
subMesh->AddFace(IndexedTriangle(0,4,5));
subMesh->AddFace(IndexedTriangle(0,5,1));{F4377 size=full}
subMesh->AddFace(IndexedTriangle(1,5,3));
subMesh->AddFace(IndexedTriangle(3,5,7));Congratulations, you have created, built and run your first Echo project!
subMesh->AddFace(IndexedTriangle(2,3,7));=What next?=
subMesh->AddFace(IndexedTriangle(2,7,6));Have a look at the project source code. The source files contain documentation about some Echo fundamentals and details the project Task structure.
mMesh.CalculateAABB();Here are some suggestions for moving forward:
//Create a basic material for the cube
shared_ptr<Material> material(new Material());
RenderPass pass;
pass.SetCullMode(RenderPass::CullModes::BACK);
pass.SetVertexColouringEnabled(true);
material->AddPass(pass);
//Set the mesh material
mMesh.SetMaterial(material);
}
AxisAlignedBox GetLocalAxisAlignedBox()
{
AxisAlignedBox box;
box.setMinimum(mMesh.GetMin());- Familiarise yourself with `Scene` objects:
box.setMaximum(mMesh.GetMax());-- Modify the scene.
return box;-- Add another `SceneEntity` to the scene, give it a `Sphere` mesh (hint: the `Mesh` class contains some helper methods for generating certain meshes).
}- Familiarise yourself with `Camera`s, `Renderer`s and `Viewport`s:
void Render(const Matrix4& transform, RenderTarget& renderTarget)-- Modify the Game state to include a third `Viewport`.
{- Familiarise yourself with GUI scripts:
SetOrientation(Quaternion(Radian(mAngle),Vector3(0.4,0.5,1)));-- In the resources folder you'll find a folder named Menu that contains various `.gui` files. These define GUI layouts of images, buttons, text etc. The element types correspond to Echo GUI classes. Play around with the menu elements.
-- Try creating a couple of new buttons to click on in the Game state to speed up or slow down the spinning cube. You will need to create a function to change the speed and set up a new binding to make it available for GUI buttons (see the application file on how to set up bindings, but set the bindings up in `Game.cpp` using the provided `FunctionBinder`).
mAngle+=0.1f;
mMesh.Render(transform * GetTransform(),renderTarget);
}
private:
Mesh mMesh;
f32 mAngle;
};- Familiarise yourself with `Task`s: Create a custom `Task` to periodically toggle the visibility of the sphere (or, if you didn't create one, the cube).
int main(int argcIf you're happy with your progress so far, const char* args[])
{
//You don't have to use a kernel object if you want to manage frame updates yourself.
Kernel kernel;
kernel.SetExecutionModel(Platform::CreateExecutionModel());
//Create a render window
shared_ptr<RenderTarget> target = Platform::CreateRenderTarget("Window",kernel,800,300,32,false);
// Renderers are used to render a camera (which renders a scene) in a viewport on a render targetyou can move onto a more advanced project by creating a third person game using the provided project template. They act as simple mapping
// objects and perform screen clearing and buffer swapping.
//
// A multirenderer will render multiple Renderer objects and control the screen clearing and buffer swapping (otherwise you would third person game template is a little more complicated that the simple application. It provides examples of:
// need to configure each Renderer yourself (which is entirely possible)- Using a `ContextSwitcher` to manage application states.
MultiRenderer renderer(target);- How you can get values from a `Configuration` object,
//- Create a scene withing a custom `Camera` controller task to follow a camera.haracter
Scene scene;- How to create and use `MappedInputDevice`s
shared_ptr<Camera> camera = scene.CreateCamera();- How to create a generic game entity class that has discrete states defined by animations, physics bodies
camera->SetPosition(0,0,10);
// Create two renderers taking half of the screen each.
renderer.CreateRenderer(make_shared<Viewport>(0,0,0.5,1),camera);
renderer.CreateRenderer(make_shared<Viewport>(0.5,0,1,1),camera);
// Add our multi-renderer as a task to the Kernel. The Renderer's Update() method will render the
// screen so you may need to set the priority of the task so it updates last.
kernel.AddTask(renderer);
// Create a spinning cube object, defined above.
shared_ptr< SpinningCube > spinningCube(new SpinningCube());
scene.AddRenderable(spinningCube);
// Start program loop
kernel.Execute();
return 0;
}
```- How to create a `BulletPhysicsWorld` and add `PhysicsBody` instances to it.