A WIP 3D game engine in C++ using OpenGL
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

592 lines
19 KiB

#include <SDL2/SDL.h>
//Using SDL, SDL OpenGL, standard IO, and, strings
#include <SDL2/SDL_mouse.h>
#include <cstdint>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <random>
#include <GL/glew.h>
#include <SDL2/SDL_opengl.h>
#include <SDL2/SDL_timer.h>
#include <GL/glu.h>
#include <stdexcept>
#include <string>
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <fmt/core.h>
#include <optional>
#include "shaders.h"
#include "mesh.h"
#include "stb_image.h"
#include "glerror.h"
#include "errors.h"
#include "glutil.h"
#include "defaultobjects/cubemap.h"
#include "drawing.h"
#include "level.h"
#include "player.h"
#include "frametime.h"
float framestep = 0.0;
class SDLGLGLWindow {
/* array buffers */
unsigned int gVBO = 0;
unsigned int quadVBO = 0;
// unsigned int gIBO = 0;
unsigned int gVAO = 0;
unsigned int quadVAO;
unsigned int texture[2];
unsigned int cubemap;
glm::vec3 cubePositions[10] = {
glm::vec3( 0.0f, 0.0f, 0.0f),
glm::vec3( 2.0f, 5.0f, -15.0f),
glm::vec3(-1.5f, -2.2f, -2.5f),
glm::vec3(-3.8f, -2.0f, -12.3f),
glm::vec3( 2.4f, -0.4f, -3.5f),
glm::vec3(-1.7f, 3.0f, -7.5f),
glm::vec3( 1.3f, -2.0f, -2.5f),
glm::vec3( 1.5f, 2.0f, -2.5f),
glm::vec3( 1.5f, 0.2f, -1.5f),
glm::vec3(-1.3f, 1.0f, -1.5f)
};
std::vector<glm::vec3> lightPositions = std::vector<glm::vec3>();
private:
public:
level * running_level;
std::shared_ptr<player::player> player_data;
Shader *skyboxShader;
Shader *texShader;
int skybox_object;
int screen_width;
int screen_height;
unsigned int framebuffer;
unsigned int textureColorBufferMultiSampledHDR;
unsigned int rbo;
unsigned int intermediateFBO;
unsigned int screenTexture;
SDL_Window *gWindow;
std::shared_ptr<player::camera> camera;
/* note:
*
* direction.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
* direction.y = sin(glm::radians(pitch));
* direction.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
*/
simple_object_draw_system *objects ;
SDLGLGLWindow(int width, int height)
{
screen_width = width;
screen_height = height;
if (!create_gl_window()) {
exit(1);
}
lightPositions.push_back(glm::vec3(5.0f, 3.0f, 5.0f));
lightPositions.push_back(glm::vec3(3.2f, 0.4f, -3.7f));
lightPositions.push_back(glm::vec3(-3.5f, 0.9f, 7.3f));
}
void update_camera() {
camera->update();
}
int create_gl_window() {
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 3 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE );
gWindow = SDL_CreateWindow( "ponder orb", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, 800, 600,
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
auto gContext = SDL_GL_CreateContext( gWindow );
if( gContext == NULL ) {
std::cerr << "OpenGL context could not be created! SDL Error: "
<< SDL_GetError() << std::endl ;
return false;
}
glewExperimental = GL_TRUE;
GLenum glewError = glewInit();
if( glewError != GLEW_OK )
{
std::cerr << "Error initializing GLEW! "
<< glewGetErrorString( glewError ) << std::endl;
}
//Use Vsync
if( SDL_GL_SetSwapInterval( 1 ) < 0 )
{
std::cerr << "Warning: Unable to set VSync! SDL Error: "
<< SDL_GetError() << std::endl;
}
// SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 2);
std::cerr << "Creating msbuffers"
<< SDL_GetError() << std::endl ;
// SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2);
std::cerr << "Creating msbuffers"
<< SDL_GetError() << std::endl ;
// now we can load level
fmt::print("loading level\n");
running_level = new level(("data/levels/init.json"));
//Initialize OpenGL
texShader = new Shader("data/shaders/screentexture.vert", "data/shaders/screentexture.frag");
skyboxShader = new Shader("data/shaders/sky.vert", "data/shaders/sky.frag");
glCheckError();
setup_msaa_framebuffers();
camera = player::get_camera();
initGL();
player_data = player::get_player();
glEnable(GL_MULTISAMPLE);
glGetError();
return true;
}
void setup_msaa_framebuffers() {
/* MSAA FRAMEBUFFERS */
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// create a multisampled color attachment texture
glGenTextures(1, &textureColorBufferMultiSampledHDR);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampledHDR);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA16F, screen_width, screen_height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampledHDR, 0);
// create a (also multisampled) renderbuffer object for depth and stencil attachments
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, screen_width, screen_height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// configure second post-processing framebuffer
glGenFramebuffers(1, &intermediateFBO);
glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
// create a color attachment texture
glGenTextures(1, &screenTexture);
glBindTexture(GL_TEXTURE_2D, screenTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, screen_width, screen_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0); // we only need a color buffer
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Intermediate framebuffer is not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
int initGL() {
bool success = true;
float cubeVertices[] = {
// vertices normals textures tangent
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
//VBO data
GLfloat quadVertices[] =
{
// Vertices // Texture Coords
-1.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
};
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
/*********** CUBES **************/
glGenVertexArrays(1, &gVAO);
glGenBuffers( 1, &gVBO );
glBindVertexArray(gVAO);
glBindBuffer(GL_ARRAY_BUFFER, gVBO);
glBufferData( GL_ARRAY_BUFFER, sizeof cubeVertices, cubeVertices, GL_STATIC_DRAW );
glCheckError();
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), NULL);
glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *)(3 * sizeof (float)));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *)(6 * sizeof(float)));
glCheckError();
glEnableVertexAttribArray(0);
glCheckError();
glEnableVertexAttribArray(1);
glCheckError();
glEnableVertexAttribArray(2);
glCheckError();
/*********** ENDCUBES **************/
/********** CUBEMAPS ***************/
;
stbi_set_flip_vertically_on_load(false);
Cubemap c (std::vector<std::string> {
fmt::format("{}/sky/right.png", SKYBOX_DIR),
fmt::format("{}/sky/left.png",SKYBOX_DIR),
fmt::format("{}/sky/up.png",SKYBOX_DIR),
fmt::format("{}/sky/down.png",SKYBOX_DIR),
fmt::format("{}/sky/front.png",SKYBOX_DIR),
fmt::format("{}/sky/back.png",SKYBOX_DIR),
});
cubemap = c.id;
/************ ENDCUBEMAP ***********/
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenVertexArrays(1, &quadVAO);
glGenBuffers( 1, &quadVBO );
glBindVertexArray(quadVAO);
glCheckError();
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData( GL_ARRAY_BUFFER, sizeof quadVertices, quadVertices, GL_STATIC_DRAW );
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof (float)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glCheckError();
return success;
}
void render()
{
auto shader = &running_level->shaders[0];
shader->use();
glCheckError();
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glEnable(GL_DEPTH_TEST);
glCheckError();
//Clear color buffer
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glCheckError();
glCheckError();
//Set vertex data
camera->set_camera(shader);
glCheckError();
/** draw skybox cubemap */
glActiveTexture(GL_TEXTURE11);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
glCheckError();
skyboxShader->use();
glDepthFunc(GL_LEQUAL);
glCheckError();
glCheckError();
skyboxShader->setInt("skybox", 11);
auto loc = skyboxShader->get_uniform("view");
glm::mat4 skybox_view = glm::mat4(glm::mat3(camera->view));
glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(skybox_view));
glCheckError();
loc = skyboxShader->get_uniform("projection");
glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(camera->projection));
glCheckError();
glBindVertexArray(gVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glCheckError();
printProgramLog(skyboxShader->program);
// draw the level objects
running_level->shader->setInt("skybox", 11);
running_level->draw(camera->view, camera->projection);
// 2. now blit multisampled buffer(s) to normal colorbuffer of intermediate FBO. Image is stored in screenTexture
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
glBlitFramebuffer(0, 0, screen_width, screen_height, 0, 0, screen_width, screen_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glCheckError();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
texShader->use();
glBindVertexArray(quadVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, screenTexture);
glDrawArrays(GL_TRIANGLES, 0, 6);
printProgramLog(texShader->program);
glCheckError();
}
void
swap_window()
{
SDL_GL_SwapWindow(gWindow);
}
~SDLGLGLWindow() {
//Deallocate program
//Destroy window
SDL_DestroyWindow( gWindow );
gWindow = NULL;
delete texShader;
delete skyboxShader;
delete running_level;
//Quit SDL subsystems
SDL_Quit();
}
};
int main(int argc, char **argv) {
SDLGLGLWindow cont {800, 600};
bool quit = false;
//Event handler
SDL_Event e;
//Enable text input
// SDL_StartTextInput();
SDL_SetRelativeMouseMode(SDL_TRUE);
bool mouse_mode = true;
std::cout << "Rendering now\n";
float last_frametime = SDL_GetTicks();
//While application is running
glm::vec3 walk_direction = {};
while( !quit )
{
bool shademode = true;
const float camera_speed = 5.4f;
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
if (e.type == SDL_KEYUP) {
switch (e.key.keysym.scancode) {
case SDL_SCANCODE_W:
walk_direction.z = 0;
// cont.player_data->move(0, glm::vec3(0,0,1));
break;
case SDL_SCANCODE_S:
walk_direction.z = 0;
//cont.player_data->move(0, glm::vec3(0,0,-1));
break;
case SDL_SCANCODE_A:
walk_direction.x = 0;
//cont.player_data->move(0, glm::vec3(-1,0,0));
break;
case SDL_SCANCODE_D:
walk_direction.x = 0;
//cont.player_data->move(0, glm::vec3(1,0,0));
break;
}
}
if (e.type == SDL_KEYDOWN) {
switch (e.key.keysym.scancode) {
case SDL_SCANCODE_X:
if ((shademode = !shademode)) {
glShadeModel(GL_FLAT);
} else {
glShadeModel(GL_SMOOTH);
}
glCheckError_("mpoo", 0);
break;
case SDL_SCANCODE_SPACE:
mouse_mode = !mouse_mode;
SDL_SetRelativeMouseMode(mouse_mode ? SDL_TRUE : SDL_FALSE);
break;
case SDL_SCANCODE_Q:
case SDL_SCANCODE_ESCAPE:
quit = true;
break;
case SDL_SCANCODE_W:
walk_direction.z = 1;
//cont.player_data->move(camera_speed, glm::vec3(0,0,1));
break;
case SDL_SCANCODE_S:
//walk_direction.x = 0;
walk_direction.z = -1;
//cont.player_data->move(camera_speed, glm::vec3(0,0,-1));
break;
case SDL_SCANCODE_A:
walk_direction.x = -1;
// cont.player_data->move(camera_speed, glm::vec3(-1,0,0));
break;
case SDL_SCANCODE_D:
walk_direction.x = 1;
//cont.player_data->move(camera_speed, glm::vec3(1,0,0));
break;
case SDL_SCANCODE_R:
glCheckError();
cont.running_level->update();
cont.initGL();
fmt::print("finished reloading level\n");
break;
}
} if (e.type == SDL_MOUSEMOTION) {
static bool first = true;
if (first) {
first = false;
continue;
}
if (mouse_mode) {
cont.camera->pitch -= e.motion.yrel * 0.1f;
cont.camera->yaw += e.motion.xrel * 0.1f;
cont.update_camera();
}
}
}
float this_frametime = SDL_GetTicks() / 1000.0;
framestep = this_frametime - last_frametime;
last_frametime = this_frametime;
cont.player_data->move(camera_speed, walk_direction);
cont.player_data->update();
cont.update_camera();
cont.render();
cont.swap_window();
}
return 0;
}