From ea55fc457b7d0068225af447da4a5c5489ccd239 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Sun, 17 Dec 2017 17:17:31 +0100 Subject: [PATCH] basic sky box --- README.md | 2 + assets | 2 +- src/app/Assets.hpp | 6 ++ src/app/app.cpp | 72 +++++++++++++++++++++ src/app/states.cpp | 8 +++ src/graphics/Camera.hpp | 1 + src/graphics/SkyBox.hpp | 58 +++++++++++++++++ src/graphics/shader.cpp | 127 ++++++++++++++++++++++++++++++++++++++ src/graphics/viewport.cpp | 6 ++ 9 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 src/graphics/SkyBox.hpp diff --git a/README.md b/README.md index 70d4af6..4f12594 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # blobs [![Build Status](https://travis-ci.org/HolySmoke86/blobs.svg?branch=master)](https://travis-ci.org/HolySmoke86/blobs) [![codecov.io](https://codecov.io/github/HolySmoke86/blobs/coverage.svg?branch=master)](https://codecov.io/github/HolySmoke86/blobs?branch=master) blobs + +Many thanks for the sky box to [StumpyStrust from opengameart.org](https://opengameart.org/content/space-skyboxes-0) diff --git a/assets b/assets index f2587b6..7c4c2fb 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit f2587b6b95d73b9b2d2d871e9a8f5b5dae702965 +Subproject commit 7c4c2fb847cfdf25d90d6b2c46442b8cf899a96a diff --git a/src/app/Assets.hpp b/src/app/Assets.hpp index 0512f7e..0d725cc 100644 --- a/src/app/Assets.hpp +++ b/src/app/Assets.hpp @@ -6,8 +6,10 @@ #include "../graphics/ArrayTexture.hpp" #include "../graphics/Canvas.hpp" #include "../graphics/CreatureSkin.hpp" +#include "../graphics/CubeMap.hpp" #include "../graphics/Font.hpp" #include "../graphics/PlanetSurface.hpp" +#include "../graphics/SkyBox.hpp" #include "../graphics/SunSurface.hpp" #include "../math/GaloisLFSR.hpp" #include "../world/Resource.hpp" @@ -29,6 +31,7 @@ struct Assets { std::string data_path; std::string font_path; std::string skin_path; + std::string sky_path; std::string tile_path; math::GaloisLFSR random; @@ -49,6 +52,7 @@ struct Assets { struct { graphics::ArrayTexture tiles; graphics::ArrayTexture skins; + graphics::CubeMap sky; } textures; struct { @@ -57,6 +61,7 @@ struct Assets { graphics::PlanetSurface planet_surface; graphics::SunSurface sun_surface; graphics::CreatureSkin creature_skin; + graphics::SkyBox sky_box; } shaders; Assets(); @@ -73,6 +78,7 @@ struct Assets { void LoadTileTexture(const std::string &name, graphics::ArrayTexture &, int layer) const; void LoadSkinTexture(const std::string &name, graphics::ArrayTexture &, int layer) const; + void LoadSkyTexture(const std::string &name, graphics::CubeMap &) const; }; diff --git a/src/app/app.cpp b/src/app/app.cpp index f847a79..0f50aa7 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -175,6 +175,7 @@ Assets::Assets() , data_path(path + "data/") , font_path(path + "fonts/") , skin_path(path + "skins/") +, sky_path(path + "skies/") , tile_path(path + "tiles/") , random(0x6283B64CEFE57925) , fonts{ @@ -223,6 +224,11 @@ Assets::Assets() LoadSkinTexture("spots", textures.skins, 4); LoadSkinTexture("circles", textures.skins, 5); textures.skins.FilterTrilinear(); + + textures.sky.Bind(); + LoadSkyTexture("blue", textures.sky); + textures.sky.FilterTrilinear(); + textures.sky.WrapEdge(); } Assets::~Assets() { @@ -385,5 +391,71 @@ void Assets::LoadSkinTexture(const string &name, graphics::ArrayTexture &tex, in SDL_FreeSurface(srf); } +void Assets::LoadSkyTexture(const string &name, graphics::CubeMap &cm) const { + string full = sky_path + name; + string right = full + "-right.png"; + string left = full + "-left.png"; + string top = full + "-top.png"; + string bottom = full + "-bottom.png"; + string back = full + "-back.png"; + string front = full + "-front.png"; + + SDL_Surface *srf = nullptr; + + if (!(srf = IMG_Load(right.c_str()))) throw SDLError("IMG_Load"); + try { + cm.Data(graphics::CubeMap::RIGHT, *srf); + } catch (...) { + SDL_FreeSurface(srf); + throw; + } + SDL_FreeSurface(srf); + + if (!(srf = IMG_Load(left.c_str()))) throw SDLError("IMG_Load"); + try { + cm.Data(graphics::CubeMap::LEFT, *srf); + } catch (...) { + SDL_FreeSurface(srf); + throw; + } + SDL_FreeSurface(srf); + + if (!(srf = IMG_Load(top.c_str()))) throw SDLError("IMG_Load"); + try { + cm.Data(graphics::CubeMap::TOP, *srf); + } catch (...) { + SDL_FreeSurface(srf); + throw; + } + SDL_FreeSurface(srf); + + if (!(srf = IMG_Load(bottom.c_str()))) throw SDLError("IMG_Load"); + try { + cm.Data(graphics::CubeMap::BOTTOM, *srf); + } catch (...) { + SDL_FreeSurface(srf); + throw; + } + SDL_FreeSurface(srf); + + if (!(srf = IMG_Load(back.c_str()))) throw SDLError("IMG_Load"); + try { + cm.Data(graphics::CubeMap::BACK, *srf); + } catch (...) { + SDL_FreeSurface(srf); + throw; + } + SDL_FreeSurface(srf); + + if (!(srf = IMG_Load(front.c_str()))) throw SDLError("IMG_Load"); + try { + cm.Data(graphics::CubeMap::FRONT, *srf); + } catch (...) { + SDL_FreeSurface(srf); + throw; + } + SDL_FreeSurface(srf); +} + } } diff --git a/src/app/states.cpp b/src/app/states.cpp index 8647ff6..3736331 100644 --- a/src/app/states.cpp +++ b/src/app/states.cpp @@ -89,6 +89,8 @@ void MasterState::OnResize(int w, int h) { assets.shaders.sun_surface.SetVP(cam.View(), cam.Projection()); assets.shaders.creature_skin.Activate(); assets.shaders.creature_skin.SetVP(cam.View(), cam.Projection()); + assets.shaders.sky_box.Activate(); + assets.shaders.sky_box.SetVP(cam.View() * cam.Universe(), cam.Projection()); } void MasterState::OnUpdate(int dt) { @@ -244,6 +246,8 @@ void MasterState::OnRender(graphics::Viewport &viewport) { cam.LookAt(glm::vec3(cam_pos), glm::vec3(cam_focus), glm::vec3(cam_up)); assets.shaders.planet_surface.Activate(); assets.shaders.planet_surface.SetV(cam.View()); + assets.shaders.sky_box.Activate(); + assets.shaders.sky_box.SetV(cam.View() * cam.Universe()); assets.shaders.sun_surface.Activate(); assets.shaders.sun_surface.SetV(cam.View()); assets.shaders.creature_skin.Activate(); @@ -306,6 +310,10 @@ void MasterState::OnRender(graphics::Viewport &viewport) { c->Draw(viewport); } + assets.shaders.sky_box.Activate(); + assets.shaders.sky_box.SetTexture(assets.textures.sky); + assets.shaders.sky_box.Draw(); + viewport.ClearDepth(); bp.Draw(viewport); cp.Draw(viewport); diff --git a/src/graphics/Camera.hpp b/src/graphics/Camera.hpp index b00d580..a3a9e57 100644 --- a/src/graphics/Camera.hpp +++ b/src/graphics/Camera.hpp @@ -39,6 +39,7 @@ public: const glm::mat4 &Projection() const noexcept { return projection; } const glm::mat4 &View() const noexcept { return view; } glm::mat4 Model(const world::Body &) const noexcept; + glm::mat4 Universe() const noexcept; private: void UpdateProjection() noexcept; diff --git a/src/graphics/SkyBox.hpp b/src/graphics/SkyBox.hpp new file mode 100644 index 0000000..8326c64 --- /dev/null +++ b/src/graphics/SkyBox.hpp @@ -0,0 +1,58 @@ +#ifndef BLOBS_GRAPHICS_SKYBOX_HPP_ +#define BLOBS_GRAPHICS_SKYBOX_HPP_ + +#include "Program.hpp" +#include "SimpleVAO.hpp" + +#include + + +namespace blobs { +namespace graphics { + +class CubeMap; + +class SkyBox { + +public: + SkyBox(); + ~SkyBox(); + + SkyBox(const SkyBox &) = delete; + SkyBox &operator =(const SkyBox &) = delete; + + SkyBox(SkyBox &&) = delete; + SkyBox &operator =(SkyBox &&) = delete; + +public: + void Activate() noexcept; + + void SetV(const glm::mat4 &v) noexcept; + void SetP(const glm::mat4 &p) noexcept; + void SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept; + void SetTexture(CubeMap &) noexcept; + + const glm::mat4 &V() const noexcept { return v; } + const glm::mat4 &P() const noexcept { return p; } + const glm::mat4 &VP() const noexcept { return vp; } + + void Draw() const noexcept; + +private: + Program prog; + + glm::mat4 v; + glm::mat4 p; + glm::mat4 vp; + + GLuint vp_handle; + GLuint sampler_handle; + + SimpleVAO vao; + +}; + +} +} + +#endif diff --git a/src/graphics/shader.cpp b/src/graphics/shader.cpp index b74d225..f68b5b5 100644 --- a/src/graphics/shader.cpp +++ b/src/graphics/shader.cpp @@ -4,9 +4,11 @@ #include "PlanetSurface.hpp" #include "Program.hpp" #include "Shader.hpp" +#include "SkyBox.hpp" #include "SunSurface.hpp" #include "ArrayTexture.hpp" +#include "CubeMap.hpp" #include "Texture.hpp" #include "../app/init.hpp" @@ -330,6 +332,131 @@ void PlanetSurface::SetNumLights(int n) noexcept { } +SkyBox::SkyBox() +: prog() +, v(1.0f) +, p(1.0f) +, vp(1.0f) { + prog.LoadShader( + GL_VERTEX_SHADER, + "#version 330 core\n" + + "layout(location = 0) in vec3 vtx_position;\n" + + "uniform mat4 VP;\n" + + "out vec3 vtx_viewspace;\n" + + "void main() {\n" + "gl_Position = VP * vec4(vtx_position, 1.0);\n" + "gl_Position.z = gl_Position.w;\n" + "vtx_viewspace = vtx_position;\n" + "}\n" + ); + prog.LoadShader( + GL_FRAGMENT_SHADER, + "#version 330 core\n" + + "in vec3 vtx_viewspace;\n" + + "uniform samplerCube tex_sampler;\n" + + "out vec3 color;\n" + + "void main() {\n" + "color = texture(tex_sampler, vtx_viewspace).rgb;\n" + "}\n" + ); + prog.Link(); + if (!prog.Linked()) { + prog.Log(std::cerr); + throw std::runtime_error("link program"); + } + vp_handle = prog.UniformLocation("VP"); + sampler_handle = prog.UniformLocation("tex_sampler"); + + vao.Bind(); + vao.BindAttributes(); + vao.EnableAttribute(0); + vao.AttributePointer(0, false, 0); + vao.ReserveAttributes(8, GL_STATIC_DRAW); + { + auto attrib = vao.MapAttributes(GL_WRITE_ONLY); + attrib[0] = glm::vec3(-1.0f, -1.0f, -1.0f); + attrib[1] = glm::vec3(-1.0f, -1.0f, 1.0f); + attrib[2] = glm::vec3(-1.0f, 1.0f, -1.0f); + attrib[3] = glm::vec3(-1.0f, 1.0f, 1.0f); + attrib[4] = glm::vec3( 1.0f, -1.0f, -1.0f); + attrib[5] = glm::vec3( 1.0f, -1.0f, 1.0f); + attrib[6] = glm::vec3( 1.0f, 1.0f, -1.0f); + attrib[7] = glm::vec3( 1.0f, 1.0f, 1.0f); + } + vao.BindElements(); + vao.ReserveElements(14, GL_STATIC_DRAW); + { + auto element = vao.MapElements(GL_WRITE_ONLY); + element[ 0] = 1; + element[ 1] = 0; + element[ 2] = 3; + element[ 3] = 2; + element[ 4] = 6; + element[ 5] = 0; + element[ 6] = 4; + element[ 7] = 1; + element[ 8] = 5; + element[ 9] = 3; + element[10] = 7; + element[11] = 6; + element[12] = 5; + element[13] = 4; + } + vao.Unbind(); +} + +SkyBox::~SkyBox() { +} + +void SkyBox::Activate() noexcept { + prog.Use(); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); +} + +void SkyBox::SetV(const glm::mat4 &vv) noexcept { + v = vv; + v[0].w = 0.0f; + v[1].w = 0.0f; + v[2].w = 0.0f; + v[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); + vp = p * v; + prog.Uniform(vp_handle, vp); +} + +void SkyBox::SetP(const glm::mat4 &pp) noexcept { + p = pp; + vp = p * v; + prog.Uniform(vp_handle, vp); +} + +void SkyBox::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept { + p = pp; + SetV(vv); +} + +void SkyBox::SetTexture(CubeMap &cm) noexcept { + glActiveTexture(GL_TEXTURE0); + cm.Bind(); + prog.Uniform(sampler_handle, GLint(0)); +} + +void SkyBox::Draw() const noexcept { + vao.Bind(); + vao.DrawTriangleStrip(14); +} + + SunSurface::SunSurface() : prog() { prog.LoadShader( diff --git a/src/graphics/viewport.cpp b/src/graphics/viewport.cpp index e4a2927..a318931 100644 --- a/src/graphics/viewport.cpp +++ b/src/graphics/viewport.cpp @@ -81,6 +81,12 @@ glm::mat4 Camera::Model(const world::Body &b) const noexcept { } } +glm::mat4 Camera::Universe() const noexcept { + return glm::mat4(track_orient + ? ref->InverseTransform() * ref->ToUniverse() + : ref->ToUniverse()); +} + void Camera::UpdateProjection() noexcept { projection = glm::infinitePerspective(fov, aspect, near); } -- 2.39.2