2019-12-13 13:26:18 +01:00
# include <iostream>
# include "ECS.h"
2020-01-03 21:41:23 +01:00
# include <glad/glad.h>
2019-12-13 13:40:41 +01:00
# include <GLFW/glfw3.h>
2020-01-03 21:41:23 +01:00
# include <GL/gl.h>
2019-12-13 13:26:18 +01:00
using namespace ECS ;
2020-01-03 21:41:23 +01:00
World * world = World : : createWorld ( ) ;
2019-12-13 13:40:41 +01:00
struct Position {
2019-12-13 13:26:18 +01:00
Position ( float x , float y , float z ) : x ( x ) , y ( y ) , z ( z ) { }
2019-12-13 13:40:41 +01:00
2019-12-13 13:26:18 +01:00
Position ( ) : x ( 0.f ) , y ( 0.f ) , z ( 0.f ) { }
float x ;
float y ;
float z ;
} ;
2020-01-03 21:41:23 +01:00
struct Movement {
Movement ( float speedX , float speedY , float speedZ ) : speedX ( speedX ) , speedY ( speedY ) , speedZ ( speedZ ) { }
float speedX ;
float speedY ;
float speedZ ;
int movingX = 0 ;
int movingY = 0 ;
int movingZ = 0 ;
float velocityX = 0.0f ;
float velocityY = 0.0f ;
float velocityZ = 0.0f ;
} ;
struct InputEvent {
int key ;
int action ;
} ;
2019-12-13 13:40:41 +01:00
class GravitySystem : public EntitySystem {
2019-12-13 13:26:18 +01:00
public :
2020-01-03 21:41:23 +01:00
explicit GravitySystem ( float amount ) {
2019-12-13 13:26:18 +01:00
gravityAmount = amount ;
}
2020-01-03 21:41:23 +01:00
void tick ( World * pWorld , float deltaTime ) override {
pWorld - > each < Position > ( [ & ] ( Entity * ent , ComponentHandle < Position > position ) {
2019-12-13 13:26:18 +01:00
position - > y + = gravityAmount * deltaTime ;
} ) ;
}
private :
float gravityAmount ;
} ;
2020-01-03 21:41:23 +01:00
class PositionDebugOutputSystem : public EntitySystem {
public :
void tick ( World * pWorld , float deltaTime ) override {
pWorld - > each < Position > ( [ & ] ( Entity * ent , ComponentHandle < Position > position ) {
std : : cout < < ent - > getEntityId ( ) < < " : "
< < position - > x < < " , "
< < position - > y < < " , "
< < position - > z
< < std : : endl ;
} ) ;
}
} ;
class KeyboardMovementSystem : public EntitySystem , public EventSubscriber < InputEvent > {
void configure ( World * pWorld ) override {
pWorld - > subscribe < InputEvent > ( this ) ;
}
void receive ( World * pWorld , const InputEvent & event ) override {
if ( event . key = = GLFW_KEY_W ) {
world - > each < Movement > ( [ & ] ( Entity * ent , ComponentHandle < Movement > movement ) {
if ( event . action = = GLFW_PRESS ) {
movement - > movingZ = - 1 ;
} else if ( event . action = = GLFW_RELEASE ) {
movement - > movingZ = 0 ;
}
} ) ;
} else if ( event . key = = GLFW_KEY_S ) {
world - > each < Movement > ( [ & ] ( Entity * ent , ComponentHandle < Movement > movement ) {
if ( event . action = = GLFW_PRESS ) {
movement - > movingZ = 1 ;
} else if ( event . action = = GLFW_RELEASE ) {
movement - > movingZ = 0 ;
}
} ) ;
} else if ( event . key = = GLFW_KEY_A ) {
world - > each < Movement > ( [ & ] ( Entity * ent , ComponentHandle < Movement > movement ) {
if ( event . action = = GLFW_PRESS ) {
movement - > movingX = 1 ;
} else if ( event . action = = GLFW_RELEASE ) {
movement - > movingX = 0 ;
}
} ) ;
} else if ( event . key = = GLFW_KEY_D ) {
world - > each < Movement > ( [ & ] ( Entity * ent , ComponentHandle < Movement > movement ) {
if ( event . action = = GLFW_PRESS ) {
movement - > movingX = - 1 ;
} else if ( event . action = = GLFW_RELEASE ) {
movement - > movingX = 0 ;
}
} ) ;
}
std : : cout < < " MyEvent was emitted! " < < std : : endl ;
}
void tick ( World * pWorld , float deltaTime ) override {
pWorld - > each < Position , Movement > (
[ & ] ( Entity * ent , ComponentHandle < Position > position , ComponentHandle < Movement > movement ) {
position - > x + = movement - > movingX * movement - > speedX * deltaTime ;
position - > y + = movement - > movingY * movement - > speedY * deltaTime ;
position - > z + = movement - > movingZ * movement - > speedZ * deltaTime ;
} ) ;
}
void unconfigure ( World * pWorld ) override {
pWorld - > unsubscribeAll ( this ) ;
}
} ;
static void key_callback ( GLFWwindow * window , int key , int scancode , int action , int mods ) {
2019-12-13 13:50:02 +01:00
if ( key = = GLFW_KEY_ESCAPE & & action = = GLFW_PRESS )
glfwSetWindowShouldClose ( window , GLFW_TRUE ) ;
2020-01-03 21:41:23 +01:00
world - > emit < InputEvent > ( { key , action } ) ;
2019-12-13 13:50:02 +01:00
}
2020-01-03 21:41:23 +01:00
const char * vertexShaderSource = " #version 330 core \n "
" layout (location = 0) in vec3 aPos; \n "
" void main() \n "
" { \n "
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); \n "
" } \0 " ;
const char * fragmentShaderSource = " #version 330 core \n "
" out vec4 FragColor; \n "
" void main() \n "
" { \n "
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); \n "
" } \n \0 " ;
2019-12-13 13:26:18 +01:00
int main ( ) {
world - > registerSystem ( new GravitySystem ( - 9.8f ) ) ;
2020-01-03 21:41:23 +01:00
world - > registerSystem ( new PositionDebugOutputSystem ( ) ) ;
world - > registerSystem ( new KeyboardMovementSystem ( ) ) ;
2019-12-13 13:26:18 +01:00
2019-12-13 13:40:41 +01:00
Entity * ent = world - > create ( ) ;
2020-01-03 21:41:23 +01:00
ent - > assign < Position > ( 0.f , 0.f , 0.f ) ;
ent - > assign < Movement > ( 1.f , 1.f , 1.f ) ;
2019-12-13 13:26:18 +01:00
ComponentHandle < Position > pos = ent - > get < Position > ( ) ;
2019-12-13 13:40:41 +01:00
GLFWwindow * window ;
/* Initialize the library */
if ( ! glfwInit ( ) )
return - 1 ;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow ( 640 , 480 , " Hello World " , NULL , NULL ) ;
if ( ! window ) {
glfwTerminate ( ) ;
return - 1 ;
}
/* Make the window's context current */
glfwMakeContextCurrent ( window ) ;
2019-12-13 13:50:02 +01:00
glfwSetKeyCallback ( window , key_callback ) ;
2020-01-03 21:41:23 +01:00
// glad: load all OpenGL function pointers
// ---------------------------------------
if ( ! gladLoadGLLoader ( ( GLADloadproc ) glfwGetProcAddress ) )
{
std : : cout < < " Failed to initialize GLAD " < < std : : endl ;
return - 1 ;
}
// build and compile our shader program
// ------------------------------------
// vertex shader
int vertexShader = glCreateShader ( GL_VERTEX_SHADER ) ;
glShaderSource ( vertexShader , 1 , & vertexShaderSource , NULL ) ;
glCompileShader ( vertexShader ) ;
// check for shader compile errors
int success ;
char infoLog [ 512 ] ;
glGetShaderiv ( vertexShader , GL_COMPILE_STATUS , & success ) ;
if ( ! success )
{
glGetShaderInfoLog ( vertexShader , 512 , NULL , infoLog ) ;
std : : cout < < " ERROR::SHADER::VERTEX::COMPILATION_FAILED \n " < < infoLog < < std : : endl ;
}
// fragment shader
int fragmentShader = glCreateShader ( GL_FRAGMENT_SHADER ) ;
glShaderSource ( fragmentShader , 1 , & fragmentShaderSource , NULL ) ;
glCompileShader ( fragmentShader ) ;
// check for shader compile errors
glGetShaderiv ( fragmentShader , GL_COMPILE_STATUS , & success ) ;
if ( ! success )
{
glGetShaderInfoLog ( fragmentShader , 512 , NULL , infoLog ) ;
std : : cout < < " ERROR::SHADER::FRAGMENT::COMPILATION_FAILED \n " < < infoLog < < std : : endl ;
}
// link shaders
int shaderProgram = glCreateProgram ( ) ;
glAttachShader ( shaderProgram , vertexShader ) ;
glAttachShader ( shaderProgram , fragmentShader ) ;
glLinkProgram ( shaderProgram ) ;
// check for linking errors
glGetProgramiv ( shaderProgram , GL_LINK_STATUS , & success ) ;
if ( ! success ) {
glGetProgramInfoLog ( shaderProgram , 512 , NULL , infoLog ) ;
std : : cout < < " ERROR::SHADER::PROGRAM::LINKING_FAILED \n " < < infoLog < < std : : endl ;
}
glDeleteShader ( vertexShader ) ;
glDeleteShader ( fragmentShader ) ;
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices [ ] = {
0.5f , 0.5f , 0.0f , // top right
0.5f , - 0.5f , 0.0f , // bottom right
- 0.5f , - 0.5f , 0.0f , // bottom left
- 0.5f , 0.5f , 0.0f // top left
} ;
unsigned int indices [ ] = { // note that we start from 0!
0 , 1 , 3 , // first Triangle
1 , 2 , 3 // second Triangle
} ;
unsigned int VBO , VAO , EBO ;
glGenVertexArrays ( 1 , & VAO ) ;
glGenBuffers ( 1 , & VBO ) ;
glGenBuffers ( 1 , & EBO ) ;
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray ( VAO ) ;
glBindBuffer ( GL_ARRAY_BUFFER , VBO ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( vertices ) , vertices , GL_STATIC_DRAW ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , EBO ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( indices ) , indices , GL_STATIC_DRAW ) ;
glVertexAttribPointer ( 0 , 3 , GL_FLOAT , GL_FALSE , 3 * sizeof ( float ) , ( void * ) 0 ) ;
glEnableVertexAttribArray ( 0 ) ;
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
// remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound.
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray ( 0 ) ;
double timeInLastFrame = glfwGetTime ( ) ;
double elapsed_time = 0.0 ;
2019-12-13 13:40:41 +01:00
/* Loop until the user closes the window */
while ( ! glfwWindowShouldClose ( window ) ) {
2020-01-03 21:41:23 +01:00
// Delta time handling
double delta = glfwGetTime ( ) - timeInLastFrame ;
timeInLastFrame = glfwGetTime ( ) ;
elapsed_time + = delta ;
std : : cout < < " Elapsed time: " < < elapsed_time < < std : : endl ;
world - > tick ( delta ) ;
2019-12-13 13:40:41 +01:00
/* Render here */
2020-01-03 21:41:23 +01:00
// render
// ------
glClearColor ( 0.2f , 0.3f , 0.3f , 1.0f ) ;
2019-12-13 13:40:41 +01:00
glClear ( GL_COLOR_BUFFER_BIT ) ;
2020-01-03 21:41:23 +01:00
// draw our first triangle
glUseProgram ( shaderProgram ) ;
glBindVertexArray ( VAO ) ; // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
//glDrawArrays(GL_TRIANGLES, 0, 6);
glDrawElements ( GL_TRIANGLES , 6 , GL_UNSIGNED_INT , 0 ) ;
// glBindVertexArray(0); // no need to unbind it every time
2019-12-13 13:40:41 +01:00
/* Swap front and back buffers */
glfwSwapBuffers ( window ) ;
/* Poll for and process events */
glfwPollEvents ( ) ;
}
glfwTerminate ( ) ;
2019-12-13 13:26:18 +01:00
return 0 ;
}