diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index b807796..1c510ab 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -10,8 +10,10 @@ set(GAME_SRC glclasses.cpp renderer.cpp game_window.cpp - triangle_window.cpp + renderer_simple.cpp + renderer_shader.cpp session.cpp + util.cpp game.cpp state/object.cpp @@ -29,6 +31,8 @@ set(GAME_HEADERS opengl.hpp glclasses.hpp renderer.hpp + renderer_simple.hpp + renderer_shader.hpp ) include_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/game/game.cpp b/game/game.cpp index 181b8ff..8931b37 100644 --- a/game/game.cpp +++ b/game/game.cpp @@ -39,7 +39,7 @@ bool Game::cycle(float dt) total += dt; float spawnInterval = 0.1; - while(acc > spawnInterval) { + while (acc > spawnInterval) { acc -= spawnInterval; float angle = 2.0 * M_PI * util::randf_0_1(); @@ -57,19 +57,20 @@ bool Game::cycle(float dt) } #endif - //std::cout<<"adding dt: " << dt << std::endl; + // std::cout<<"adding dt: " << dt << std::endl; m_time_for_next_step += dt; int steps = 0; - while(m_time_for_next_step >= m_time_step) { - //std::cout<<"time now: " << m_time_for_next_step << std::endl; + while (m_time_for_next_step >= m_time_step) { + // std::cout<<"time now: " << m_time_for_next_step << std::endl; m_time_for_next_step -= m_time_step; m_state->advance(m_time_step); steps++; } - //std::cout << m_time_for_next_step << " s remaining time, " << steps << " steps taken." << std::endl; + // std::cout << m_time_for_next_step << " s remaining time, " << steps << " + // steps taken." << std::endl; return true; } diff --git a/game/game.hpp b/game/game.hpp index 36a1de6..707e713 100644 --- a/game/game.hpp +++ b/game/game.hpp @@ -3,7 +3,7 @@ #include "state/state.hpp" class Game { -public: + public: Game(); // main method of the game. run this regulary @@ -13,7 +13,7 @@ public: // for rendering game::State *state() const { return m_state; } -private: + private: game::State *m_state; float m_time_for_next_step; diff --git a/game/game_window.hpp b/game/game_window.hpp index defd766..e54f39f 100644 --- a/game/game_window.hpp +++ b/game/game_window.hpp @@ -2,6 +2,8 @@ #include "opengl.hpp" #include "renderer.hpp" +#include "renderer_simple.hpp" +#include "renderer_shader.hpp" #include "game.hpp" @@ -14,8 +16,11 @@ #include "state/explosion.hpp" class GameWindow : public endofthejedi::GLWindow { -private: -protected: + private: + Game* m_game; + endofthejedi::RendererSimple m_renderer; + + protected: void init() override { glClearColor(0.5f, 0.6f, 0.7f, 1.0f); resize(); @@ -24,95 +29,29 @@ protected: } void render(double time) override { - //static bool once = false; - //if (!once) { + // static bool once = false; + // if (!once) { // once = true; // for (int i=0; i<1000; i++) { // m_game->cycle(time); // } //} - if (!m_game->cycle(static_cast(time/1000000000.0))) { - std::cout<<"stopping the game..." << std::endl; + if (!m_game->cycle(static_cast(time / 1000000000.0))) { + std::cout << "stopping the game..." << std::endl; stop(); } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - for (const game::Planet *planet : m_game->state()->planets) { - drawPlanet(planet->position, planet->radius); - } - - for (const game::Trace *trace : m_game->state()->traces) { - drawTrace(trace); - } - - for (const game::Explosion *explosion : m_game->state()->explosions) { - drawExplosion(explosion); - } - - for (const game::Ship *ship : m_game->state()->ships) { - drawShip(ship->position); - } - - for (const game::Player *player : m_game->state()->players) { - for (const game::Missile *missile : player->missiles) { - drawMissile(missile->position); - } - } + m_renderer.render(m_game->state()); } void resize() override { glViewport(0, 0, getwidth(), getheight()); } - void drawShip(const glm::vec2 &pos) - { - //std::cout<<"draw ship @ " << pos.x << ", " << pos.y << std::endl; - glm::vec3 color = glm::vec3(0.2, 1.0, 0.3); - - float radius = m_game->state()->shipRadius(); - - m_renderer.drawCircle(pos.x, pos.y, radius, color.x, color.y, color.z, 12); + public: + GameWindow(unsigned int width, unsigned int height, Game *ptr) + : endofthejedi::GLWindow(width, height) { + m_game = ptr; } - - void drawPlanet(const glm::vec2 &pos, float radius) - { - glm::vec3 color = glm::vec3(0.7, 0.1, 0.2); - - //std::cout<<"draw planet @ " << pos.x << ", " << pos.y << std::endl; - m_renderer.drawCircle(pos.x, pos.y, radius, color.x, color.y, color.z, 32); - } - - void drawMissile(const glm::vec2 &pos) - { - glm::vec3 color = glm::vec3(1.0, 1.0, 0.3); - m_renderer.drawCircle(pos.x, pos.y, 0.01, color.x, color.y, color.z, 6); - } - - void drawTrace(const game::Trace *trace) - { - for (const game::Trace::TracePoint &p : trace->points) { - glm::vec3 color = glm::vec3(0.1, 0.3, 1.0) / (1.0f + 500.0f*p.speed); - m_renderer.drawCircle(p.position.x, p.position.y, 0.005, color.x, color.y, color.z, 3); - } - } - - void drawExplosion(const game::Explosion *explosion) - { - // TODO: transparent - // TODO: with glow in the middle - float r = explosion->maxRadius * (explosion->age / explosion->maxAge); - - // TODO: transparency? - glm::vec3 color = glm::vec3(1.0, 0.9, 0.1); - m_renderer.drawCircle(explosion->position.x, explosion->position.y, r, color.x, color.y, color.z, 64); - } - -public: - GameWindow(unsigned int width, unsigned int height, Game* game) - : endofthejedi::GLWindow(width, height) { m_game = game; } - -private: - Game *m_game; - endofthejedi::Renderer m_renderer; }; - diff --git a/game/glclasses.cpp b/game/glclasses.cpp index 2d6e618..0733c47 100644 --- a/game/glclasses.cpp +++ b/game/glclasses.cpp @@ -1,5 +1,8 @@ #include "glclasses.hpp" +#include +#include + endofthejedi::VAO::VAO() { glGenVertexArrays(1, &m_name); } endofthejedi::VAO::~VAO() { glDeleteVertexArrays(1, &m_name); } @@ -9,31 +12,66 @@ void endofthejedi::VAO::bind() { glBindVertexArray(m_name); } void endofthejedi::VAO::fill(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) { - glEnableVertexAttribArray(index); - glVertexAttribPointer(index, size, GL_FLOAT, normalized, stride, pointer); + glEnableVertexAttribArray(index); + glVertexAttribPointer(index, size, GL_FLOAT, normalized, stride, pointer); } -endofthejedi::Shader::Shader() { - m_program = glCreateProgram(); -} +endofthejedi::Shader::Shader() { m_program = glCreateProgram(); } endofthejedi::Shader::~Shader() {} -void endofthejedi::Shader::bind() { - glUseProgram(m_program); +bool endofthejedi::Shader::check() { + GLint len = 0; + GLint result = 0; + + glGetProgramiv(m_program, GL_LINK_STATUS, &result); + glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &len); + if (len > 1) { + char *error = (char *)malloc(len); + glGetProgramInfoLog(m_program, len, NULL, error); + std::string str(error); + std::cout << str << "\n"; + } + std::cout << "checked program" + << "\n"; + + return (bool)result; } -void endofthejedi::Shader::unbind() { - glUseProgram(0); +bool endofthejedi::Shader::checkShader(GLuint shader) { + GLint len = 0; + GLint result = 0; + + glGetShaderiv(shader, GL_COMPILE_STATUS, &result); + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); + if (len > 1) { + char *error = (char *)malloc(len+1); + glGetShaderInfoLog(shader, 0, &len, error); + std::string str(error, error + len); + std::cout << str << "\n"; + } + std::cout << "checked shader" + << "\n"; + + return (bool)result; } +void endofthejedi::Shader::bind() { glUseProgram(m_program); } + +void endofthejedi::Shader::unbind() { glUseProgram(0); } + void endofthejedi::Shader::load(std::string path, GLenum shadertype) { - GLuint cheddar = glCreateShader(shadertype); - const char* cheddardata = path.c_str(); - glShaderSource(cheddar, 1, &cheddardata, NULL); - glCompileShader(cheddar); - glAttachShader(m_program, cheddar); - glLinkProgram(m_program); - glDeleteShader(cheddar); + GLuint cheddar = glCreateShader(shadertype); + const char *cheddardata = path.c_str(); + glShaderSource(cheddar, 1, &cheddardata, NULL); + glCompileShader(cheddar); + checkShader(cheddar); + glAttachShader(m_program, cheddar); + glLinkProgram(m_program); + check(); + glDeleteShader(cheddar); } +GLuint endofthejedi::Shader::location(std::string name) { + return glGetUniformLocation(m_program, name.c_str()); +} diff --git a/game/glclasses.hpp b/game/glclasses.hpp index 4f546ec..7280425 100644 --- a/game/glclasses.hpp +++ b/game/glclasses.hpp @@ -8,51 +8,57 @@ namespace endofthejedi { template class BufferObject { - private: - GLuint m_name; - GLvoid* m_mappointer; - protected: - public: - BufferObject(); - ~BufferObject(); - void bind(); - void bind(GLuint index, GLintptr offset = 0, GLsizeiptr size = 0); - void fill(GLenum usage, GLsizei size = 0, GLvoid* data = NULL); - void subfill(GLintptr offset, GLsizei size, const GLvoid* data); - void map(GLenum access); - void unmap(); + private: + GLuint m_name; + GLvoid *m_mappointer; + + protected: + public: + BufferObject(); + ~BufferObject(); + void bind(); + void bind(GLuint index, GLintptr offset = 0, GLsizeiptr size = 0); + void fill(GLenum usage, GLsizei size = 0, GLvoid *data = NULL); + void subfill(GLintptr offset, GLsizei size, const GLvoid *data); + void map(GLenum access); + void unmap(); }; typedef BufferObject VBO; typedef BufferObject IBO; class VAO { - private: - GLuint m_name; - protected: - public: - VAO(); - ~VAO(); - void bind(); - void fill(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride = 0, const GLvoid* pointer = NULL); + private: + GLuint m_name; + + protected: + public: + VAO(); + ~VAO(); + void bind(); + void fill(GLuint index, GLint size, GLenum type, GLboolean normalized, + GLsizei stride = 0, const GLvoid *pointer = NULL); }; - class Shader { - private: - GLuint m_program; - protected: - public: - Shader(); - ~Shader(); - void bind(); - void unbind(); - void load(std::string data, GLenum shadertype); - }; +class Shader { + private: + GLuint m_program; + bool check(); + bool checkShader(GLuint shader); + protected: + public: + Shader(); + ~Shader(); + void bind(); + void unbind(); + void load(std::string data, GLenum shadertype); + GLuint location(std::string name); +}; } -#define TBufferObject_(pre, post) \ - template pre endofthejedi::BufferObject::post +#define TBufferObject_(pre, post) \ + template pre endofthejedi::BufferObject::post #define TBufferObject(...) TBufferObject_(__VA_ARGS__) TBufferObject(, BufferObject)() { glGenBuffers(1, &m_name); } @@ -62,22 +68,22 @@ TBufferObject(, ~BufferObject)() { glDeleteBuffers(1, &m_name); } TBufferObject(void, bind)() { glBindBuffer(T, m_name); } TBufferObject(void, bind)(GLuint index, GLintptr offset, GLsizeiptr size) { - // todo + // todo } TBufferObject(void, fill)(GLenum usage, GLsizei size, GLvoid *data) { - glBufferData(T, size, data, usage); + glBufferData(T, size, data, usage); } TBufferObject(void, subfill)(GLintptr offset, GLsizei size, const GLvoid *data) { - glBufferSubData(T, offset, size, data); + glBufferSubData(T, offset, size, data); } TBufferObject(void, map)(GLenum access) { - // todo + // todo } TBufferObject(void, unmap)() { - // todo + // todo } diff --git a/game/opengl.cpp b/game/opengl.cpp index 0ac19ad..ee32a5c 100644 --- a/game/opengl.cpp +++ b/game/opengl.cpp @@ -3,100 +3,101 @@ #include #include #include +#include "options.hpp" -#define UNUSED(foo) (void)foo; +#define UNUSED(foo) (void) foo; timespec diff(timespec start, timespec end) { - timespec result; - if ((end.tv_nsec - start.tv_nsec) < 0) { - result.tv_sec = end.tv_sec - start.tv_sec - 1; - result.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; - } else { - result.tv_sec = end.tv_sec - start.tv_sec; - result.tv_nsec = end.tv_nsec - start.tv_nsec; - } - return result; + timespec result; + if ((end.tv_nsec - start.tv_nsec) < 0) { + result.tv_sec = end.tv_sec - start.tv_sec - 1; + result.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; + } else { + result.tv_sec = end.tv_sec - start.tv_sec; + result.tv_nsec = end.tv_nsec - start.tv_nsec; + } + return result; } endofthejedi::GLWindow::GLWindow(unsigned int width, unsigned int height) : m_width(width), m_height(height) { - m_display = XOpenDisplay(NULL); + m_display = XOpenDisplay(NULL); - if (m_display == NULL) { - throw std::runtime_error("XOpenDisplay NULL"); - } + if (m_display == NULL) { + throw std::runtime_error("XOpenDisplay NULL"); + } - m_rootwnd = DefaultRootWindow(m_display); + m_rootwnd = DefaultRootWindow(m_display); - m_visualinfo = glXChooseVisual(m_display, 0, m_attributes); + m_visualinfo = glXChooseVisual(m_display, 0, m_attributes); - if (m_visualinfo == NULL) { - throw std::runtime_error("glXChooseVisual NULL"); - } + if (m_visualinfo == NULL) { + throw std::runtime_error("glXChooseVisual NULL"); + } - m_colormap = - XCreateColormap(m_display, m_rootwnd, m_visualinfo->visual, AllocNone); + m_colormap = + XCreateColormap(m_display, m_rootwnd, m_visualinfo->visual, AllocNone); - m_swa.colormap = m_colormap; - m_swa.event_mask = ExposureMask | KeyPressMask; + m_swa.colormap = m_colormap; + m_swa.event_mask = ExposureMask | KeyPressMask; - m_window = XCreateWindow( - m_display, m_rootwnd, 0, 0, width, height, 0, m_visualinfo->depth, - InputOutput, m_visualinfo->visual, CWColormap | CWEventMask, &m_swa); + m_window = XCreateWindow( + m_display, m_rootwnd, 0, 0, width, height, 0, m_visualinfo->depth, + InputOutput, m_visualinfo->visual, CWColormap | CWEventMask, &m_swa); - m_atomWmDeleteWindow = XInternAtom(m_display, "WM_DELETE_WINDOW", False); - XSetWMProtocols(m_display, m_window, &m_atomWmDeleteWindow, 1); + m_atomWmDeleteWindow = XInternAtom(m_display, "WM_DELETE_WINDOW", False); + XSetWMProtocols(m_display, m_window, &m_atomWmDeleteWindow, 1); - XMapWindow(m_display, m_window); - XStoreName(m_display, m_window, "NAME"); + XMapWindow(m_display, m_window); + XStoreName(m_display, m_window, "NAME"); - m_glcontext = glXCreateContext(m_display, m_visualinfo, NULL, GL_TRUE); + m_glcontext = glXCreateContext(m_display, m_visualinfo, NULL, GL_TRUE); - XSync(m_display, False); + XSync(m_display, False); - glXMakeCurrent(m_display, m_window, m_glcontext); + glXMakeCurrent(m_display, m_window, m_glcontext); - std::cout << "GL Renderer: " << glGetString(GL_RENDERER) << "\n"; - std::cout << "GL Version: " << glGetString(GL_VERSION) << "\n"; - std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) - << "\n"; + std::cout << "GL Renderer: " << glGetString(GL_RENDERER) << "\n"; + std::cout << "GL Version: " << glGetString(GL_VERSION) << "\n"; + std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) + << "\n"; - init(); + init(); - XClearWindow(m_display, m_window); - XMapRaised(m_display, m_window); + XClearWindow(m_display, m_window); + XMapRaised(m_display, m_window); } endofthejedi::GLWindow::~GLWindow() { - glXMakeCurrent(m_display, None, NULL); - glXDestroyContext(m_display, m_glcontext); - XFree(m_visualinfo); - XDestroyWindow(m_display, m_window); - XCloseDisplay(m_display); + glXMakeCurrent(m_display, None, NULL); + glXDestroyContext(m_display, m_glcontext); + XFree(m_visualinfo); + XDestroyWindow(m_display, m_window); + XCloseDisplay(m_display); } void endofthejedi::GLWindow::handleevents() { - if (XPending(m_display) > 0) { - XEvent xev; - XNextEvent(m_display, &xev); - handle(xev); - } + if (XPending(m_display) > 0) { + XEvent xev; + XNextEvent(m_display, &xev); + handle(xev); + } } void endofthejedi::GLWindow::handle(XEvent event) { - if (event.type == Expose) { - XWindowAttributes attribs; - XGetWindowAttributes(m_display, m_window, &attribs); - m_width = attribs.width; - m_height = attribs.height; - resize(); - } else if (event.type == ClientMessage) { - if (event.xclient.data.l[0] == m_atomWmDeleteWindow) { - stop(); + if (event.type == Expose) { + XWindowAttributes attribs; + XGetWindowAttributes(m_display, m_window, &attribs); + m_width = attribs.width; + m_height = attribs.height; + resize(); + } else if (event.type == ClientMessage) { + if (event.xclient.data.l[0] == m_atomWmDeleteWindow) { + stop(); + } + } else if (event.type == DestroyNotify) { + stop(); } - } else if (event.type == DestroyNotify) { - stop(); - } } void endofthejedi::GLWindow::swap() { glXSwapBuffers(m_display, m_window); } diff --git a/game/opengl.hpp b/game/opengl.hpp index d6aed00..c9b36e9 100644 --- a/game/opengl.hpp +++ b/game/opengl.hpp @@ -1,5 +1,4 @@ #pragma once - #include #include #include diff --git a/game/raycaster.fs b/game/raycaster.fs new file mode 100644 index 0000000..9f7e2df --- /dev/null +++ b/game/raycaster.fs @@ -0,0 +1,234 @@ +R"raw_string( +#version 120 + +struct intersection +{ + bool intersected; + vec3 point; + vec3 normal; + vec3 color; + float reflection; + int idx; + //todo different types +}; + +varying vec2 outvertex; + +//settings +uniform float aspectratio; +uniform float time; +uniform int supersamples; +uniform int reflections; +uniform bool shadows; +uniform vec3 backgroundcolor; + +//light +uniform vec3 l_position; +uniform float l_radius; + +//spheres +//todo ubo? +uniform int s_length; +uniform vec3 s_positions[100]; +uniform float s_radii[100]; +uniform vec4 s_colors[100]; +uniform float s_reflections[100]; + +const float PI = 3.14159265359; + +//din = german industrial normal +float light_diffuse(vec3 pos, vec3 din) +{ + vec3 l_dir = normalize(l_position - pos); + return max(dot(l_dir, din), 0.0f); +} + +//adapted from https://wiki.delphigl.com/index.php/shader_ConeVolumeShadow +float light_shadow(vec3 pos) +{ + float s = 1.0f; + + for(int l = 0; l < s_length; l++) + { + vec3 s_pos = s_positions[l]; + float s_rad = s_radii[l]; + + // project fragment (pos) on the cone axis => F_ + vec3 nvLO = s_pos - l_position; + float dLO = length(nvLO); + nvLO /= dLO; + vec3 vLF = pos - l_position; + float dLF_ = dot(vLF, nvLO); + if (dLF_ < dLO) { + // fragment before occluder => no shadow + continue; + } + vec3 F_ = l_position + dLF_ * nvLO; + float rF = distance(F_, pos); + + // compute outer and inner radius at F_ + float rF_outer = (s_rad + l_radius) * (dLF_ / dLO) - l_radius; + if (rF >= rF_outer) { + // outside the outer cone => no shadow + continue; + } + float rF_inner = (s_rad - l_radius) * (dLF_ / dLO) + l_radius; + if (rF_inner >= rF) { + // inside the inner cone => full shadow + return 0.0; + } + else if (rF_inner >= 0.0 || rF >= -rF_inner) { + // soft shadow, linear interpolation + s *= (rF - rF_inner) / (rF_outer - rF_inner); + } + else { + // light from both sides of the occluder + s *= (-2.0*rF_inner) / (rF_outer - rF_inner); + } + + } + + return s; +} + +intersection intersect_sphere(vec3 r_pos, vec3 r_dir, vec3 s_pos, float s_rad, inout float minimum) +{ + intersection result = intersection(false,vec3(0.0f, 0.0f, 0.0f), + vec3(0.0f, 0.0f, 0.0f), + vec3(0.0f, 0.0f, 0.0f), 0.0f, -1); + + vec3 v = r_pos - s_pos; + float a = dot(r_pos, r_pos); + float b = dot(v, r_dir); + float c = dot(v, v) - (s_rad * s_rad); + float d = b * b - c; + + if(d >= 0) + { + float w1 = -b - sqrt(d); + float w2 = -b + sqrt(d); + + if(w1 > 0.0f || w2 > 0.0f) + { + float w = min(w1, w2); + float o = max(w1, w2); + + if(w1 <= 0.0f) + w = w2; + else + if(w2 <= 0.0f) + w = w1; + + if(w < minimum) + { + minimum = w; + } + else + { + return intersection(false,vec3(0.0f, 0.0f, 0.0f), + vec3(0.0f, 0.0f, 0.0f), + vec3(0.0f, 0.0f, 0.0f), 0.0f, -1); + } + + vec3 p = r_pos + (w * r_dir); + result.intersected = true; + result.point = p; + result.normal = normalize((p - s_pos) / s_rad); + return result; + } + } + + return result; +} + +intersection intersect(vec3 r_pos, vec3 r_dir, int idx) +{ + intersection result = intersection(false,vec3(0.0f, 0.0f, 0.0f), + vec3(0.0f, 0.0f, 0.0f), + vec3(0.0f, 0.0f, 0.0f), 0.0f, -1); + float minimum = 1000.0f; + + for(int l = 0; l < s_length; l++) + { + if(idx == l) + continue; + + float maximum; + + intersection r = intersect_sphere(r_pos, r_dir, s_positions[l], s_radii[l], minimum); + if(r.intersected) + { + r.color = s_colors[l].rgb; + r.idx = l; + r.reflection = s_reflections[l]; + + result = r; + } + //todo other geometric objects + //todo handle min with other geometric objects + } + + return result; +} + +vec3 cast_ray(vec3 r_pos, vec3 r_pixel) +{ + vec3 r_dir = normalize(r_pixel - r_pos); + + vec3 color = backgroundcolor; + + intersection i = intersection(false,vec3(0.0f, 0.0f, 0.0f), + vec3(0.0f, 0.0f, 0.0f), + vec3(0.0f, 0.0f, 0.0f), 0.0f, -1); + + vec3 p = r_pos; + vec3 d = r_dir; + int idx = -1; + + for(int bounce = 0; bounce < reflections; bounce++) + { + intersection i = intersect(p,d, idx); + + if(i.intersected) + { + float l_factor = light_diffuse(i.point, i.normal); + + if(shadows && l_factor > 0.004f) + { + l_factor *= light_shadow(i.point); + } + + if(bounce == 0) + { + color = i.color * l_factor; + } + else + { + color = mix(color, color * i.color * l_factor, i.reflection); + } + + //d = 2*(dot(p, i.normal))*i.normal - p; + d = reflect(-p, i.normal); + p = i.point; + idx = i.idx; + } + else + break; + } + + return color; +} + +void main() +{ + vec2 rp = outvertex; + rp.x = rp.x * aspectratio; + vec4 outcolor = vec4(cast_ray(vec3(0.0f, 0.0f, 1.0f), vec3(rp, 0.0f)), 0.0f); + for(int supersample = 1; supersample < supersamples; supersample++) + { + outcolor = mix(outcolor, vec4(cast_ray(vec3(sin(supersample * PI/supersamples)/200, cos(supersample * PI/supersamples)/200, 1.0f), vec3(rp, 0.0f)), 0.0f), 0.5f); + } + gl_FragColor = outcolor; +} + +)raw_string" diff --git a/game/raycaster.vs b/game/raycaster.vs new file mode 100644 index 0000000..1dd8fbe --- /dev/null +++ b/game/raycaster.vs @@ -0,0 +1,13 @@ +R"raw_string( +#version 120 + +attribute vec2 invertex; +varying vec2 outvertex; + +void main() { + gl_Position.xy = invertex; + gl_Position.zw = vec2(0.0f, 1.0); + outvertex = invertex; +} + +)raw_string" \ No newline at end of file diff --git a/game/renderer.cpp b/game/renderer.cpp index 6a7b4ba..cdc854a 100644 --- a/game/renderer.cpp +++ b/game/renderer.cpp @@ -1,18 +1,4 @@ #include "renderer.hpp" -endofthejedi::Renderer::Renderer() { - -} - -endofthejedi::Renderer::~Renderer() {} - -void endofthejedi::Renderer::drawCircle(float x, float y, float radius, float r, float g, float b, int numSides) -{ - glBegin(GL_TRIANGLE_FAN); - glColor3f(r,g,b); - glVertex2f(x, y); // center of circle - for (int i = 0; i <= numSides; i++) { - glVertex2f(x + (radius * cos(i * 2 * M_PI / numSides)), y + (radius * sin(i * 2 * M_PI / numSides))); - } - glEnd(); +void endofthejedi::Renderer::render(const game::State *state) { } diff --git a/game/renderer.hpp b/game/renderer.hpp index 387d606..88c0b45 100644 --- a/game/renderer.hpp +++ b/game/renderer.hpp @@ -5,21 +5,15 @@ #include #include -#include "glclasses.hpp" +#include "game.hpp" namespace endofthejedi { class Renderer { - private: - VBO m_vbo; - VAO m_vao; - Shader m_shader; - protected: - public: - Renderer(); - ~Renderer(); - void drawCircle(float x, float y, float radius, float r, - float g, float b, int numSides=12); + private: + protected: + public: + virtual void render(const game::State *state); }; } diff --git a/game/renderer_shader.cpp b/game/renderer_shader.cpp new file mode 100644 index 0000000..47beaf5 --- /dev/null +++ b/game/renderer_shader.cpp @@ -0,0 +1,75 @@ +#include "renderer_shader.hpp" + +#include +#include "glm/glm.hpp" +#include "glm/vec2.hpp" +#include "glm/vec3.hpp" +#include "glm/gtc/type_ptr.hpp" + +endofthejedi::RendererShader::RendererShader() { + m_shader.load(vss, GL_VERTEX_SHADER); + m_shader.load(fss, GL_FRAGMENT_SHADER); +} + +void endofthejedi::RendererShader::render(const game::State *state) { + m_shader.bind(); + + std::vector positions; + std::vector colors; + std::vector radii; + std::vector reflections; + + for (const game::Planet *planet : state->planets) { + positions.push_back(glm::vec3(planet->position, -5.0f)); + radii.push_back(planet->radius); + colors.push_back(glm::vec4(1.0f, 0.0f, 0.0f, 0.5f)); + } + + for (const game::Ship *ship : state->ships) { + positions.push_back(glm::vec3(ship->position, -3.0f)); + radii.push_back(ship->radius); + colors.push_back(glm::vec4(1.0f, 0.0f, 0.0f, 0.5f)); + } + + for (const game::Player *player : state->players) { + for (const game::Missile *missile : player->missiles) { + positions.push_back(glm::vec3(missile->position, -3.0f)); + radii.push_back(0.01f); + colors.push_back(glm::vec4(1.0f, 0.0f, 0.0f, 0.5f)); + } + } + + for (auto &pos : positions) { + pos.x *= 5; + pos.y *= 5; + } + for (auto &rad : radii) { + rad *= 5; + } + + /* + for (const game::Trace *trace : state->traces) { + positions.push_back(glm::vec3(trace->position, -3.0f)); + radii.push_back(trace->radius); + colors.push_back(glm::vec4(0.0f, 1.0f, 0.0f, 0.5f)); + }*/ + + glUniform1f(m_shader.location("aspectratio"), 1.0f); + glUniform1i(m_shader.location("reflections"), 1); + glUniform3f(m_shader.location("l_position"), 0.6f, 0.1f, 0.0f); + glUniform1f(m_shader.location("l_radius"), 1.0f); + glUniform3fv(m_shader.location("s_positions"), positions.size(), + glm::value_ptr(positions[0])); + glUniform4fv(m_shader.location("s_colors"), colors.size(), + glm::value_ptr(colors[0])); + glUniform1fv(m_shader.location("s_radii"), radii.size(), &radii[0]); + glUniform1i(m_shader.location("s_length"), positions.size()); + + // render fullscreen quad with legacy opengl (too lazy, sorry) + glBegin(GL_QUADS); + glVertex2f(-1.0f, -1.0f); + glVertex2f(1.0f, -1.0f); + glVertex2f(1.0f, 1.0f); + glVertex2f(-1.0f, 1.0f); + glEnd(); +} diff --git a/game/renderer_shader.hpp b/game/renderer_shader.hpp new file mode 100644 index 0000000..2287740 --- /dev/null +++ b/game/renderer_shader.hpp @@ -0,0 +1,30 @@ +#pragma once + +static const char *vss = +#include "raycaster.vs" + ; +static const char *fss = +#include "raycaster.fs" + ; + +#include "renderer.hpp" + +#include "glclasses.hpp" +#include "game.hpp" +#include "state/planet.hpp" +#include "state/trace.hpp" +#include "state/player.hpp" +#include "state/ship.hpp" + +namespace endofthejedi { + + class RendererShader : Renderer { + private: + Shader m_shader; + protected: + public: + RendererShader(); + void render(const game::State *state) override; + }; + +} diff --git a/game/renderer_simple.cpp b/game/renderer_simple.cpp new file mode 100644 index 0000000..197001c --- /dev/null +++ b/game/renderer_simple.cpp @@ -0,0 +1,79 @@ +#include "renderer_simple.hpp" + +void endofthejedi::RendererSimple::drawCircle(float x, float y, float radius, + float r, float g, float b, + int numSides) { + glBegin(GL_TRIANGLE_FAN); + glColor3f(r, g, b); + glVertex2f(x, y); // center of circle + for (int i = 0; i <= numSides; i++) { + glVertex2f(x + (radius * cos(i * 2 * M_PI / numSides)), + y + (radius * sin(i * 2 * M_PI / numSides))); + } + glEnd(); +} + +void endofthejedi::RendererSimple::drawShip(const glm::vec2 &pos, + float radius) { + // std::cout<<"draw ship @ " << pos.x << ", " << pos.y << std::endl; + glm::vec3 color = glm::vec3(0.2, 1.0, 0.3); + + drawCircle(pos.x, pos.y, radius, color.x, color.y, color.z, 12); +} + +void endofthejedi::RendererSimple::drawPlanet(const glm::vec2 &pos, + float radius) { + glm::vec3 color = glm::vec3(0.7, 0.1, 0.2); + + // std::cout<<"draw planet @ " << pos.x << ", " << pos.y << std::endl; + drawCircle(pos.x, pos.y, radius, color.x, color.y, color.z, 32); +} + +void endofthejedi::RendererSimple::drawMissile(const glm::vec2 &pos) { + glm::vec3 color = glm::vec3(1.0, 1.0, 0.3); + drawCircle(pos.x, pos.y, 0.01, color.x, color.y, color.z, 6); +} + +void endofthejedi::RendererSimple::drawTrace(const game::Trace *trace) { + for (const game::Trace::TracePoint &p : trace->points) { + glm::vec3 color = glm::vec3(0.1, 0.3, 1.0) / (1.0f + 500.0f * p.speed); + drawCircle(p.position.x, p.position.y, 0.005, color.x, color.y, color.z, + 3); + } +} + +void endofthejedi::RendererSimple::drawExplosion( + const game::Explosion *explosion) { + // TODO: transparent + // TODO: with glow in the middle + float r = explosion->maxRadius * (explosion->age / explosion->maxAge); + + // TODO: transparency? + glm::vec3 color = glm::vec3(1.0, 0.9, 0.1); + drawCircle(explosion->position.x, explosion->position.y, r, color.x, + color.y, color.z, 64); +} + +void endofthejedi::RendererSimple::render(const game::State *state) { + for (const game::Planet *planet : state->planets) { + drawPlanet(planet->position, planet->radius); + } + + for (const game::Trace *trace : state->traces) { + drawTrace(trace); + } + + for (const game::Explosion *explosion : state->explosions) { + drawExplosion(explosion); + } + + for (const game::Ship *ship : state->ships) { + drawShip(ship->position, ship->radius); + } + + for (const game::Player *player : state->players) { + for (const game::Missile *missile : player->missiles) { + drawMissile(missile->position); + } + } +} diff --git a/game/renderer_simple.hpp b/game/renderer_simple.hpp new file mode 100644 index 0000000..b62a650 --- /dev/null +++ b/game/renderer_simple.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "renderer.hpp" + +#include "glclasses.hpp" + +#include "game.hpp" +#include "state/trace.hpp" +#include "state/object.hpp" +#include "state/missile.hpp" +#include "state/player.hpp" +#include "state/planet.hpp" +#include "state/ship.hpp" +#include "state/explosion.hpp" + +namespace endofthejedi { + +class RendererSimple : Renderer { + private: + void drawCircle(float x, float y, float radius, float r, float g, float b, + int numSides = 12); + void drawShip(const glm::vec2 &pos, float radius); + void drawPlanet(const glm::vec2 &pos, float radius); + void drawMissile(const glm::vec2 &pos); + void drawTrace(const game::Trace *trace); + void drawExplosion(const game::Explosion *explosion); + + protected: + public: + void render(const game::State *state) override; +}; + +} diff --git a/game/session.hpp b/game/session.hpp index 23a8a49..730dc93 100644 --- a/game/session.hpp +++ b/game/session.hpp @@ -1,5 +1,7 @@ #pragma once +#define ASIO_STANDALONE + #include #include #include diff --git a/game/triangle_window.cpp b/game/triangle_window.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/game/triangle_window.hpp b/game/triangle_window.hpp deleted file mode 100644 index e35d2e4..0000000 --- a/game/triangle_window.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "opengl.hpp" - -class TriangleWindow : public endofthejedi::GLWindow { -private: -protected: - void init() override { - glClearColor(0.5f, 0.6f, 0.7f, 1.0f); - resize(); - - glEnable(GL_DEPTH_TEST); - } - void render(double time) override { - (void) time; - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glBegin(GL_TRIANGLES); - glColor3f(1.0f, 0.0f, 0.0f); - glVertex3f(0.0f, -1.0f, 0.0f); - glColor3f(0.0f, 1.0f, 0.0f); - glVertex3f(-1.0f, 1.0f, 0.0f); - glColor3f(0.0f, 0.0f, 1.0f); - glVertex3f(1.0f, 1.0f, 0.0f); - glEnd(); - } - void resize() override { glViewport(0, 0, getwidth(), getheight()); } - -public: - TriangleWindow(unsigned int width, unsigned int height) - : endofthejedi::GLWindow(width, height) - { - } -}; -