From: Daniel Karbach Date: Sat, 8 Aug 2015 21:13:45 +0000 (+0200) Subject: textures X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=7bb75960dbf9bfdee9ac865384aca81791b3da5c;p=blank.git textures textures textures textures textures --- diff --git a/TODO b/TODO index 8cea292..f3c43c6 100644 --- a/TODO +++ b/TODO @@ -10,7 +10,7 @@ composite entity animations textures - do I need to say anything? :) + okay, now I need a better solution for the crosshair ^^ font rendering diff --git a/assets b/assets index 96db33a..449410e 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 96db33a3047bf3f20f5b6d4464cf4a4ee238146d +Subproject commit 449410ec8e8e4b4bd7878b99aef9dc77ed422ff1 diff --git a/src/ai/Spawner.cpp b/src/ai/Spawner.cpp index 612c3cc..b0b9bcb 100644 --- a/src/ai/Spawner.cpp +++ b/src/ai/Spawner.cpp @@ -105,7 +105,7 @@ void Spawner::Spawn(const glm::ivec3 &chunk, const glm::vec3 &pos) { e.Position(chunk, pos); e.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } }); e.WorldCollidable(true); - e.SetShape(world.BlockTypes()[1].shape, color); + e.SetShape(world.BlockTypes()[1].shape, color, 2); e.AngularVelocity(rot); Controller *ctrl; if (rand() % 2) { diff --git a/src/app/Assets.hpp b/src/app/Assets.hpp index 4953ddb..6e1698a 100644 --- a/src/app/Assets.hpp +++ b/src/app/Assets.hpp @@ -6,8 +6,10 @@ namespace blank { +class ArrayTexture; class Font; class Sound; +class Texture; class Assets { @@ -16,10 +18,13 @@ public: Font LoadFont(const std::string &name, int size) const; Sound LoadSound(const std::string &name) const; + Texture LoadTexture(const std::string &name) const; + void LoadTexture(const std::string &name, ArrayTexture &, int layer) const; private: std::string fonts; std::string sounds; + std::string textures; }; diff --git a/src/app/WorldState.cpp b/src/app/WorldState.cpp index 6ca9959..b686ab2 100644 --- a/src/app/WorldState.cpp +++ b/src/app/WorldState.cpp @@ -13,7 +13,7 @@ WorldState::WorldState( const World::Config &wc ) : env(env) -, world(wc) +, world(env.assets, wc) , spawner(world) , interface(ic, env, world) { diff --git a/src/app/app.cpp b/src/app/app.cpp index 420dee7..f3c9115 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -7,12 +7,15 @@ #include "init.hpp" #include "../audio/Sound.hpp" +#include "../graphics/ArrayTexture.hpp" #include "../graphics/Font.hpp" +#include "../graphics/Texture.hpp" #include "../world/BlockType.hpp" #include "../world/Entity.hpp" #include #include +#include using std::string; @@ -195,7 +198,8 @@ void StateControl::Commit(Application &app) { Assets::Assets(const string &base) : fonts(base + "fonts/") -, sounds(base + "sounds/") { +, sounds(base + "sounds/") +, textures(base + "textures/") { } @@ -209,6 +213,35 @@ Sound Assets::LoadSound(const string &name) const { return Sound(full.c_str()); } +Texture Assets::LoadTexture(const string &name) const { + string full = textures + name + ".png"; + Texture tex; + SDL_Surface *srf = IMG_Load(full.c_str()); + if (!srf) { + throw SDLError("IMG_Load"); + } + tex.Bind(); + tex.Data(*srf); + SDL_FreeSurface(srf); + return tex; +} + +void Assets::LoadTexture(const string &name, ArrayTexture &tex, int layer) const { + string full = textures + name + ".png"; + SDL_Surface *srf = IMG_Load(full.c_str()); + if (!srf) { + throw SDLError("IMG_Load"); + } + tex.Bind(); + try { + tex.Data(layer, *srf); + } catch (...) { + SDL_FreeSurface(srf); + throw; + } + SDL_FreeSurface(srf); +} + void FrameCounter::EnterFrame() noexcept { last_enter = SDL_GetTicks(); diff --git a/src/graphics/ArrayTexture.hpp b/src/graphics/ArrayTexture.hpp new file mode 100644 index 0000000..93b560e --- /dev/null +++ b/src/graphics/ArrayTexture.hpp @@ -0,0 +1,51 @@ +#ifndef BLANK_GRAPHICS_ARRAYTEXTURE_HPP_ +#define BLANK_GRAPHICS_ARRAYTEXTURE_HPP_ + +#include "Format.hpp" + +#include + +struct SDL_Surface; + + +namespace blank { + +class ArrayTexture { + +public: + ArrayTexture(); + ~ArrayTexture(); + + ArrayTexture(ArrayTexture &&) noexcept; + ArrayTexture &operator =(ArrayTexture &&) noexcept; + + ArrayTexture(const ArrayTexture &) = delete; + ArrayTexture &operator =(const ArrayTexture &) = delete; + +public: + GLsizei Width() const noexcept { return width; } + GLsizei Height() const noexcept { return height; } + GLsizei Depth() const noexcept { return depth; } + + void Bind() noexcept; + + void Reserve(GLsizei w, GLsizei h, GLsizei d, const Format &) noexcept; + void Data(GLsizei l, const SDL_Surface &); + void Data(GLsizei l, const Format &, GLvoid *data) noexcept; + + void FilterNearest() noexcept; + void FilterLinear() noexcept; + void FilterTrilinear() noexcept; + +private: + GLuint handle; + + GLsizei width, height, depth; + + Format format; + +}; + +} + +#endif diff --git a/src/graphics/BlockLighting.hpp b/src/graphics/BlockLighting.hpp index 321cf79..9b3e8af 100644 --- a/src/graphics/BlockLighting.hpp +++ b/src/graphics/BlockLighting.hpp @@ -9,6 +9,8 @@ namespace blank { +class ArrayTexture; + class BlockLighting { public: @@ -16,6 +18,7 @@ public: void Activate() noexcept; + void SetTexture(ArrayTexture &) noexcept; void SetFogDensity(float) noexcept; void SetM(const glm::mat4 &m) noexcept; @@ -37,6 +40,7 @@ private: GLuint mv_handle; GLuint mvp_handle; + GLuint sampler_handle; GLuint light_direction_handle; GLuint light_color_handle; GLuint fog_density_handle; diff --git a/src/graphics/DirectionalLighting.hpp b/src/graphics/DirectionalLighting.hpp index e42d2cf..70492ef 100644 --- a/src/graphics/DirectionalLighting.hpp +++ b/src/graphics/DirectionalLighting.hpp @@ -9,6 +9,8 @@ namespace blank { +class ArrayTexture; + class DirectionalLighting { public: @@ -19,6 +21,7 @@ public: void SetLightDirection(const glm::vec3 &) noexcept; void SetLightColor(const glm::vec3 &) noexcept; + void SetTexture(ArrayTexture &) noexcept; void SetFogDensity(float) noexcept; void SetM(const glm::mat4 &m) noexcept; @@ -41,6 +44,7 @@ private: GLuint m_handle; GLuint mv_handle; GLuint mvp_handle; + GLuint sampler_handle; GLuint light_direction_handle; GLuint light_color_handle; GLuint fog_density_handle; diff --git a/src/graphics/Format.hpp b/src/graphics/Format.hpp index 26ebfe0..5762aab 100644 --- a/src/graphics/Format.hpp +++ b/src/graphics/Format.hpp @@ -13,7 +13,12 @@ struct Format { GLenum type; GLenum internal; - void ReadPixelFormat(const SDL_PixelFormat &); + SDL_PixelFormat sdl_format; + + Format(); + explicit Format(const SDL_PixelFormat &); + + bool Compatible(const Format &other) const noexcept; }; diff --git a/src/graphics/Texture.hpp b/src/graphics/Texture.hpp index 240e145..9e24a8d 100644 --- a/src/graphics/Texture.hpp +++ b/src/graphics/Texture.hpp @@ -1,8 +1,6 @@ #ifndef BLANK_GRAPHICS_TEXTURE_HPP_ #define BLANK_GRAPHICS_TEXTURE_HPP_ -#include "Format.hpp" - #include struct SDL_Surface; @@ -10,6 +8,8 @@ struct SDL_Surface; namespace blank { +struct Format; + class Texture { public: diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index be59d23..470cb19 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -1,9 +1,11 @@ -#include "BlendedSprite.hpp" +#include "ArrayTexture.hpp" #include "Font.hpp" #include "Format.hpp" #include "Texture.hpp" #include "Viewport.hpp" +#include "../app/init.hpp" + #include #include #include @@ -126,8 +128,32 @@ void Font::Render(const char *text, Texture &tex) const { SDL_FreeSurface(srf); } - -void Format::ReadPixelFormat(const SDL_PixelFormat &fmt) { +Format::Format() +: format(GL_BGRA) +, type(GL_UNSIGNED_INT_8_8_8_8_REV) +, internal(GL_RGBA8) { + sdl_format.format = SDL_PIXELFORMAT_ARGB8888; + sdl_format.palette = nullptr; + sdl_format.BitsPerPixel = 32; + sdl_format.BytesPerPixel = 4; + sdl_format.Rmask = 0x00FF0000; + sdl_format.Gmask = 0x0000FF00; + sdl_format.Bmask = 0x000000FF; + sdl_format.Amask = 0xFF000000; + sdl_format.Rloss = 0; + sdl_format.Gloss = 0; + sdl_format.Bloss = 0; + sdl_format.Aloss = 0; + sdl_format.Rshift = 16; + sdl_format.Gshift = 8; + sdl_format.Bshift = 0; + sdl_format.Ashift = 24; + sdl_format.refcount = 1; + sdl_format.next = nullptr; +} + +Format::Format(const SDL_PixelFormat &fmt) +: sdl_format(fmt) { if (fmt.BytesPerPixel == 4) { if (fmt.Amask == 0xFF) { if (fmt.Rmask == 0xFF00) { @@ -156,6 +182,10 @@ void Format::ReadPixelFormat(const SDL_PixelFormat &fmt) { } } +bool Format::Compatible(const Format &other) const noexcept { + return format == other.format && type == other.type && internal == other.internal; +} + Texture::Texture() : handle(0) @@ -197,8 +227,7 @@ namespace { } void Texture::Data(const SDL_Surface &srf, bool pad2) noexcept { - Format format; - format.ReadPixelFormat(*srf.format); + Format format(*srf.format); if (!pad2 || (ispow2(srf.w) && ispow2(srf.h))) { int align = UnpackAlignmentFromPitch(srf.pitch); @@ -296,4 +325,110 @@ void Texture::UnpackRowLength(GLint i) noexcept { glPixelStorei(GL_UNPACK_ROW_LENGTH, i); } + +ArrayTexture::ArrayTexture() +: handle(0) +, width(0) +, height(0) +, depth(0) { + glGenTextures(1, &handle); +} + +ArrayTexture::~ArrayTexture() { + if (handle != 0) { + glDeleteTextures(1, &handle); + } +} + +ArrayTexture::ArrayTexture(ArrayTexture &&other) noexcept +: handle(other.handle) { + other.handle = 0; + width = other.width; + height = other.height; + depth = other.depth; +} + +ArrayTexture &ArrayTexture::operator =(ArrayTexture &&other) noexcept { + std::swap(handle, other.handle); + width = other.width; + height = other.height; + depth = other.depth; + return *this; +} + + +void ArrayTexture::Bind() noexcept { + glBindTexture(GL_TEXTURE_2D_ARRAY, handle); +} + + +void ArrayTexture::Reserve(GLsizei w, GLsizei h, GLsizei d, const Format &f) noexcept { + glTexStorage3D( + GL_TEXTURE_2D_ARRAY, // which + 1, // mipmap count + f.internal, // format + w, h, // dimensions + d // layer count + ); + width = w; + height = h; + depth = d; + format = f; +} + +void ArrayTexture::Data(GLsizei l, const SDL_Surface &srf) { + Format fmt(*srf.format); + if (format.Compatible(fmt)) { + Data(l, fmt, srf.pixels); + } else { + SDL_Surface *converted = SDL_ConvertSurface( + const_cast(&srf), + &format.sdl_format, + 0 + ); + if (!converted) { + throw SDLError("SDL_ConvertSurface"); + } + Format new_fmt(*converted->format); + if (!format.Compatible(new_fmt)) { + SDL_FreeSurface(converted); + throw std::runtime_error("unable to convert texture input"); + } + Data(l, new_fmt, converted->pixels); + SDL_FreeSurface(converted); + } +} + +void ArrayTexture::Data(GLsizei l, const Format &f, GLvoid *data) noexcept { + glTexSubImage3D( + GL_TEXTURE_2D_ARRAY, // which + 0, // mipmap lavel + 0, 0, // dest X and Y offset + l, // layer offset + width, height, + 1, // layer count + f.format, f.type, + data + ); +} + + +void ArrayTexture::FilterNearest() noexcept { + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +} + +void ArrayTexture::FilterLinear() noexcept { + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +} + +void ArrayTexture::FilterTrilinear() noexcept { + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); +} + } diff --git a/src/graphics/shader.cpp b/src/graphics/shader.cpp index 03b2edc..938dc97 100644 --- a/src/graphics/shader.cpp +++ b/src/graphics/shader.cpp @@ -4,6 +4,7 @@ #include "Program.hpp" #include "Shader.hpp" +#include "ArrayTexture.hpp" #include "Texture.hpp" #include "../app/init.hpp" @@ -181,11 +182,13 @@ DirectionalLighting::DirectionalLighting() GL_VERTEX_SHADER, "#version 330 core\n" "layout(location = 0) in vec3 vtx_position;\n" - "layout(location = 1) in vec3 vtx_color;\n" - "layout(location = 2) in vec3 vtx_normal;\n" + "layout(location = 1) in vec3 vtx_tex_uv;\n" + "layout(location = 2) in vec3 vtx_color;\n" + "layout(location = 3) in vec3 vtx_normal;\n" "uniform mat4 M;\n" "uniform mat4 MV;\n" "uniform mat4 MVP;\n" + "out vec3 frag_tex_uv;\n" "out vec3 frag_color;\n" "out vec3 vtx_viewspace;\n" "out vec3 normal;\n" @@ -193,28 +196,33 @@ DirectionalLighting::DirectionalLighting() "gl_Position = MVP * vec4(vtx_position, 1);\n" "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n" "normal = (M * vec4(vtx_normal, 0)).xyz;\n" + "frag_tex_uv = vtx_tex_uv;\n" "frag_color = vtx_color;\n" "}\n" ); program.LoadShader( GL_FRAGMENT_SHADER, "#version 330 core\n" + "in vec3 frag_tex_uv;\n" "in vec3 frag_color;\n" "in vec3 vtx_viewspace;\n" "in vec3 normal;\n" + "uniform sampler2DArray tex_sampler;\n" "uniform vec3 light_direction;\n" "uniform vec3 light_color;\n" "uniform float fog_density;\n" "out vec3 color;\n" "void main() {\n" - "vec3 ambient = vec3(0.1, 0.1, 0.1) * frag_color;\n" + "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n" + "vec3 base_color = tex_color * frag_color;\n" + "vec3 ambient = vec3(0.1, 0.1, 0.1) * base_color;\n" // this should be the same as the clear color, otherwise looks really weird "vec3 fog_color = vec3(0, 0, 0);\n" "float e = 2.718281828;\n" "vec3 n = normalize(normal);\n" "vec3 l = normalize(light_direction);\n" "float cos_theta = clamp(dot(n, l), 0, 1);\n" - "vec3 reflect_color = ambient + frag_color * light_color * cos_theta;\n" + "vec3 reflect_color = ambient + base_color * light_color * cos_theta;\n" "float value = pow(e, -pow(fog_density * length(vtx_viewspace), 5));" "color = mix(fog_color, reflect_color, value);\n" "}\n" @@ -228,6 +236,7 @@ DirectionalLighting::DirectionalLighting() m_handle = program.UniformLocation("M"); mv_handle = program.UniformLocation("MV"); mvp_handle = program.UniformLocation("MVP"); + sampler_handle = program.UniformLocation("tex_sampler"); light_direction_handle = program.UniformLocation("light_direction"); light_color_handle = program.UniformLocation("light_color"); fog_density_handle = program.UniformLocation("fog_density"); @@ -257,6 +266,12 @@ void DirectionalLighting::SetLightColor(const glm::vec3 &col) noexcept { program.Uniform(light_color_handle, col); } +void DirectionalLighting::SetTexture(ArrayTexture &tex) noexcept { + glActiveTexture(GL_TEXTURE0); + tex.Bind(); + program.Uniform(sampler_handle, GLint(0)); +} + void DirectionalLighting::SetFogDensity(float f) noexcept { program.Uniform(fog_density_handle, f); } @@ -293,15 +308,18 @@ BlockLighting::BlockLighting() GL_VERTEX_SHADER, "#version 330 core\n" "layout(location = 0) in vec3 vtx_position;\n" - "layout(location = 1) in vec3 vtx_color;\n" - "layout(location = 2) in float vtx_light;\n" + "layout(location = 1) in vec3 vtx_tex_uv;\n" + "layout(location = 2) in vec3 vtx_color;\n" + "layout(location = 3) in float vtx_light;\n" "uniform mat4 MV;\n" "uniform mat4 MVP;\n" + "out vec3 frag_tex_uv;\n" "out vec3 frag_color;\n" "out vec3 vtx_viewspace;\n" "out float frag_light;\n" "void main() {\n" "gl_Position = MVP * vec4(vtx_position, 1);\n" + "frag_tex_uv = vtx_tex_uv;\n" "frag_color = vtx_color;\n" "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n" "frag_light = vtx_light;\n" @@ -310,18 +328,20 @@ BlockLighting::BlockLighting() program.LoadShader( GL_FRAGMENT_SHADER, "#version 330 core\n" + "in vec3 frag_tex_uv;\n" "in vec3 frag_color;\n" "in vec3 vtx_viewspace;\n" "in float frag_light;\n" + "uniform sampler2DArray tex_sampler;\n" "uniform float fog_density;\n" "out vec3 color;\n" "void main() {\n" - "vec3 ambient = vec3(0.1, 0.1, 0.1) * frag_color;\n" + "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n" + "vec3 base_color = tex_color * frag_color;\n" "float light_power = clamp(pow(0.8, 15 - frag_light), 0, 1);\n" "vec3 fog_color = vec3(0, 0, 0);\n" "float e = 2.718281828;\n" - //"vec3 reflect_color = ambient + frag_color * light_power;\n" - "vec3 reflect_color = frag_color * light_power;\n" + "vec3 reflect_color = base_color * light_power;\n" "float value = pow(e, -pow(fog_density * length(vtx_viewspace), 5));" "color = mix(fog_color, reflect_color, value);\n" "}\n" @@ -334,6 +354,7 @@ BlockLighting::BlockLighting() mv_handle = program.UniformLocation("MV"); mvp_handle = program.UniformLocation("MVP"); + sampler_handle = program.UniformLocation("tex_sampler"); fog_density_handle = program.UniformLocation("fog_density"); } @@ -342,15 +363,21 @@ void BlockLighting::Activate() noexcept { program.Use(); } -void BlockLighting::SetM(const glm::mat4 &m) noexcept { - program.Uniform(mv_handle, view * m); - program.Uniform(mvp_handle, vp * m); +void BlockLighting::SetTexture(ArrayTexture &tex) noexcept { + glActiveTexture(GL_TEXTURE0); + tex.Bind(); + program.Uniform(sampler_handle, GLint(0)); } void BlockLighting::SetFogDensity(float f) noexcept { program.Uniform(fog_density_handle, f); } +void BlockLighting::SetM(const glm::mat4 &m) noexcept { + program.Uniform(mv_handle, view * m); + program.Uniform(mvp_handle, vp * m); +} + void BlockLighting::SetProjection(const glm::mat4 &p) noexcept { projection = p; vp = p * view; diff --git a/src/model/BlockModel.hpp b/src/model/BlockModel.hpp index 0d93758..2ffd816 100644 --- a/src/model/BlockModel.hpp +++ b/src/model/BlockModel.hpp @@ -14,17 +14,20 @@ class BlockModel { public: using Position = glm::vec3; + using TexCoord = glm::vec3; using Color = glm::vec3; using Light = float; using Index = unsigned int; using Positions = std::vector; + using TexCoords = std::vector; using Colors = std::vector; using Lights = std::vector; using Indices = std::vector; enum Attribute { ATTRIB_VERTEX, + ATTRIB_TEXCOORD, ATTRIB_COLOR, ATTRIB_LIGHT, ATTRIB_INDEX, @@ -34,12 +37,14 @@ public: struct Buffer { Positions vertices; + TexCoords tex_coords; Colors colors; Lights lights; Indices indices; void Clear() noexcept { vertices.clear(); + tex_coords.clear(); colors.clear(); lights.clear(); indices.clear(); @@ -47,6 +52,7 @@ public: void Reserve(size_t p, size_t i) { vertices.reserve(p); + tex_coords.reserve(p); colors.reserve(p); lights.reserve(p); indices.reserve(i); diff --git a/src/model/EntityModel.hpp b/src/model/EntityModel.hpp index bd56a43..ce4ce1f 100644 --- a/src/model/EntityModel.hpp +++ b/src/model/EntityModel.hpp @@ -14,17 +14,20 @@ class EntityModel { public: using Position = glm::vec3; + using TexCoord = glm::vec3; using Color = glm::vec3; using Normal = glm::vec3; using Index = unsigned int; using Positions = std::vector; + using TexCoords = std::vector; using Colors = std::vector; using Normals = std::vector; using Indices = std::vector; enum Attribute { ATTRIB_VERTEX, + ATTRIB_TEXCOORD, ATTRIB_COLOR, ATTRIB_NORMAL, ATTRIB_INDEX, @@ -34,12 +37,14 @@ public: struct Buffer { Positions vertices; + TexCoords tex_coords; Colors colors; Normals normals; Indices indices; void Clear() noexcept { vertices.clear(); + tex_coords.clear(); colors.clear(); normals.clear(); indices.clear(); @@ -47,6 +52,7 @@ public: void Reserve(size_t p, size_t i) { vertices.reserve(p); + tex_coords.reserve(p); colors.reserve(p); normals.reserve(p); indices.reserve(i); diff --git a/src/model/Shape.hpp b/src/model/Shape.hpp index c6964f9..51b950f 100644 --- a/src/model/Shape.hpp +++ b/src/model/Shape.hpp @@ -5,7 +5,6 @@ #include "EntityModel.hpp" #include "OutlineModel.hpp" -#include #include @@ -31,21 +30,19 @@ struct Shape { /// fill given buffers with this shape's elements with an /// optional transform and offset void Vertices( - EntityModel::Positions &vertex, - EntityModel::Normals &normal, - EntityModel::Indices &index + EntityModel::Buffer &out, + float tex_offset = 0.0f ) const; void Vertices( - EntityModel::Positions &vertex, - EntityModel::Normals &normal, - EntityModel::Indices &index, + EntityModel::Buffer &out, const glm::mat4 &transform, + float tex_offset = 0.0f, EntityModel::Index idx_offset = 0 ) const; void Vertices( - BlockModel::Positions &vertex, - BlockModel::Indices &index, + BlockModel::Buffer &out, const glm::mat4 &transform, + float tex_offset = 0.0f, BlockModel::Index idx_offset = 0 ) const; @@ -57,8 +54,7 @@ struct Shape { /// fill given buffers with this shape's outline's elements with /// an optional offset void Outline( - OutlineModel::Positions &vertex, - OutlineModel::Indices &index, + OutlineModel::Buffer &out, const OutlineModel::Position &offset = { 0.0f, 0.0f, 0.0f }, OutlineModel::Index idx_offset = 0 ) const; @@ -85,21 +81,23 @@ struct Shape { ) const noexcept = 0; protected: - void SetShape(const EntityModel::Positions &pos, const EntityModel::Normals &nrm, const EntityModel::Indices &idx) { - vtx_pos = pos; - vtx_nrm = nrm; - vtx_idx = idx; - } - void SetOutline(const OutlineModel::Positions &pos, const OutlineModel::Indices &idx) { - out_pos = pos; - out_idx = idx; - } + void SetShape( + const EntityModel::Positions &pos, + const EntityModel::Normals &nrm, + const EntityModel::Indices &idx); + void SetTexture( + const BlockModel::TexCoords &tex_coords); + void SetOutline( + const OutlineModel::Positions &pos, + const OutlineModel::Indices &idx); private: EntityModel::Positions vtx_pos; EntityModel::Normals vtx_nrm; EntityModel::Indices vtx_idx; + BlockModel::TexCoords vtx_tex_coords; + OutlineModel::Positions out_pos; OutlineModel::Indices out_idx; diff --git a/src/model/model.cpp b/src/model/model.cpp index b834298..72de1da 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -11,6 +11,9 @@ namespace blank { void EntityModel::Update(const Buffer &buf) noexcept { #ifndef NDEBUG + if (buf.tex_coords.size() < buf.vertices.size()) { + std::cerr << "EntityModel: not enough tex coords!" << std::endl; + } if (buf.colors.size() < buf.vertices.size()) { std::cerr << "EntityModel: not enough colors!" << std::endl; } @@ -21,6 +24,7 @@ void EntityModel::Update(const Buffer &buf) noexcept { vao.Bind(); vao.PushAttribute(ATTRIB_VERTEX, buf.vertices); + vao.PushAttribute(ATTRIB_TEXCOORD, buf.tex_coords); vao.PushAttribute(ATTRIB_COLOR, buf.colors); vao.PushAttribute(ATTRIB_NORMAL, buf.normals); vao.PushIndices(ATTRIB_INDEX, buf.indices); @@ -34,6 +38,9 @@ void EntityModel::Draw() const noexcept { void BlockModel::Update(const Buffer &buf) noexcept { #ifndef NDEBUG + if (buf.tex_coords.size() < buf.vertices.size()) { + std::cerr << "BlockModel: not enough tex coords!" << std::endl; + } if (buf.colors.size() < buf.vertices.size()) { std::cerr << "BlockModel: not enough colors!" << std::endl; } @@ -44,6 +51,7 @@ void BlockModel::Update(const Buffer &buf) noexcept { vao.Bind(); vao.PushAttribute(ATTRIB_VERTEX, buf.vertices); + vao.PushAttribute(ATTRIB_TEXCOORD, buf.tex_coords); vao.PushAttribute(ATTRIB_COLOR, buf.colors); vao.PushAttribute(ATTRIB_LIGHT, buf.lights); vao.PushIndices(ATTRIB_INDEX, buf.indices); diff --git a/src/model/shape.cpp b/src/model/shape.cpp index e9364bd..aeea644 100644 --- a/src/model/shape.cpp +++ b/src/model/shape.cpp @@ -5,67 +5,97 @@ namespace blank { void Shape::Vertices( - EntityModel::Positions &vertex, - EntityModel::Normals &normal, - EntityModel::Indices &index + EntityModel::Buffer &out, + float tex_offset ) const { for (const auto &pos : vtx_pos) { - vertex.emplace_back(pos); + out.vertices.emplace_back(pos); + } + for (const auto &coord : vtx_tex_coords) { + out.tex_coords.emplace_back(coord.x, coord.y, coord.z + tex_offset); } for (const auto &nrm : vtx_nrm) { - normal.emplace_back(nrm); + out.normals.emplace_back(nrm); } for (auto idx : vtx_idx) { - index.emplace_back(idx); + out.indices.emplace_back(idx); } } void Shape::Vertices( - EntityModel::Positions &vertex, - EntityModel::Normals &normal, - EntityModel::Indices &index, + EntityModel::Buffer &out, const glm::mat4 &transform, + float tex_offset, EntityModel::Index idx_offset ) const { for (const auto &pos : vtx_pos) { - vertex.emplace_back(transform * glm::vec4(pos, 1.0f)); + out.vertices.emplace_back(transform * glm::vec4(pos, 1.0f)); + } + for (const auto &coord : vtx_tex_coords) { + out.tex_coords.emplace_back(coord.x, coord.y, coord.z + tex_offset); } for (const auto &nrm : vtx_nrm) { - normal.emplace_back(transform * glm::vec4(nrm, 0.0f)); + out.normals.emplace_back(transform * glm::vec4(nrm, 0.0f)); } for (auto idx : vtx_idx) { - index.emplace_back(idx_offset + idx); + out.indices.emplace_back(idx_offset + idx); } } void Shape::Vertices( - BlockModel::Positions &vertex, - BlockModel::Indices &index, + BlockModel::Buffer &out, const glm::mat4 &transform, + float tex_offset, BlockModel::Index idx_offset ) const { for (const auto &pos : vtx_pos) { - vertex.emplace_back(transform * glm::vec4(pos, 1.0f)); + out.vertices.emplace_back(transform * glm::vec4(pos, 1.0f)); + } + for (const auto &coord : vtx_tex_coords) { + out.tex_coords.emplace_back(coord.x, coord.y, coord.z + tex_offset); } for (auto idx : vtx_idx) { - index.emplace_back(idx_offset + idx); + out.indices.emplace_back(idx_offset + idx); } } void Shape::Outline( - OutlineModel::Positions &vertex, - OutlineModel::Indices &index, + OutlineModel::Buffer &out, const OutlineModel::Position &elem_offset, OutlineModel::Index idx_offset ) const { for (const auto &pos : out_pos) { - vertex.emplace_back(elem_offset + pos); + out.vertices.emplace_back(elem_offset + pos); } for (auto idx : out_idx) { - index.emplace_back(idx_offset + idx); + out.indices.emplace_back(idx_offset + idx); } } +void Shape::SetShape( + const EntityModel::Positions &pos, + const EntityModel::Normals &nrm, + const EntityModel::Indices &idx +) { + vtx_pos = pos; + vtx_nrm = nrm; + vtx_idx = idx; +} + +void Shape::SetTexture( + const BlockModel::TexCoords &tex_coords +) { + vtx_tex_coords = tex_coords; +} + +void Shape::SetOutline( + const OutlineModel::Positions &pos, + const OutlineModel::Indices &idx +) { + out_pos = pos; + out_idx = idx; +} + NullShape::NullShape() : Shape() { @@ -153,6 +183,32 @@ CuboidShape::CuboidShape(const AABB &b) 16, 17, 18, 18, 17, 19, // left 20, 21, 22, 22, 21, 23, // right }); + SetTexture({ + { 0.0f, 1.0f, 0.0f }, // front + { 1.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 1.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 0.0f }, // back + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, // top + { 0.0f, 1.0f, 0.0f }, + { 1.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 0.0f }, + { 1.0f, 0.0f, 0.0f }, // bottom + { 0.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, // left + { 1.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 1.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 0.0f }, // right + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + }); SetOutline({ { bb.min.x, bb.min.y, bb.min.z }, // back { bb.max.x, bb.min.y, bb.min.z }, @@ -286,6 +342,48 @@ StairShape::StairShape(const AABB &bb, const glm::vec2 &clip) 32, 33, 34, 34, 33, 35, // right, upper 36, 37, 38, 38, 37, 39, // right, lower }); + SetTexture({ + { 0.0f, 0.5f, 0.0f }, // front, upper + { 1.0f, 0.5f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, // front, lower + { 1.0f, 1.0f, 0.0f }, + { 0.0f, 0.5f, 0.0f }, + { 1.0f, 0.5f, 0.0f }, + { 1.0f, 1.0f, 0.0f }, // back + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, // top, upper + { 0.0f, 0.5f, 0.0f }, + { 1.0f, 0.0f, 0.0f }, + { 1.0f, 0.5f, 0.0f }, + { 0.0f, 0.5f, 0.0f }, // top, lower + { 0.0f, 1.0f, 0.0f }, + { 1.0f, 0.5f, 0.0f }, + { 1.0f, 1.0f, 0.0f }, + { 1.0f, 0.0f, 0.0f }, // bottom + { 0.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.5f, 0.0f }, // left, upper + { 0.5f, 0.5f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.5f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, // left, lower + { 1.0f, 1.0f, 0.0f }, + { 0.0f, 0.5f, 0.0f }, + { 1.0f, 0.5f, 0.0f }, + { 1.0f, 0.5f, 0.0f }, // right, upper + { 1.0f, 0.0f, 0.0f }, + { 0.5f, 0.5f, 0.0f }, + { 0.5f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 0.0f }, // right, lower + { 1.0f, 0.5f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.5f, 0.0f }, + }); SetOutline({ { bot.min.x, bot.min.y, bot.min.z }, // bottom { bot.max.x, bot.min.y, bot.min.z }, diff --git a/src/world/BlockType.hpp b/src/world/BlockType.hpp index 786c76c..95a9605 100644 --- a/src/world/BlockType.hpp +++ b/src/world/BlockType.hpp @@ -17,6 +17,7 @@ namespace blank { struct BlockType { const Shape *shape; + float texture; glm::vec3 color; glm::vec3 outline_color; diff --git a/src/world/Entity.cpp b/src/world/Entity.cpp index 4a34a11..072bb38 100644 --- a/src/world/Entity.cpp +++ b/src/world/Entity.cpp @@ -30,10 +30,10 @@ Entity::Entity() noexcept } -void Entity::SetShape(const Shape *s, const glm::vec3 &color) { +void Entity::SetShape(const Shape *s, const glm::vec3 &color, float texture) { shape = s; model_buffer.Clear(); - shape->Vertices(model_buffer.vertices, model_buffer.normals, model_buffer.indices); + shape->Vertices(model_buffer, texture); model_buffer.colors.resize(shape->VertexCount(), color); model.Update(model_buffer); } diff --git a/src/world/Entity.hpp b/src/world/Entity.hpp index 078daa6..f60bf4c 100644 --- a/src/world/Entity.hpp +++ b/src/world/Entity.hpp @@ -22,7 +22,7 @@ public: bool HasShape() const noexcept { return shape; } const Shape *GetShape() const noexcept { return shape; } - void SetShape(const Shape *, const glm::vec3 &color); + void SetShape(const Shape *, const glm::vec3 &color, float texture); void SetShapeless() noexcept; const std::string &Name() const noexcept { return name; } diff --git a/src/world/World.cpp b/src/world/World.cpp index e8b665c..73a870d 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -1,6 +1,8 @@ #include "World.hpp" #include "WorldCollision.hpp" +#include "../app/Assets.hpp" +#include "../graphics/Format.hpp" #include "../graphics/Viewport.hpp" #include @@ -11,11 +13,12 @@ namespace blank { -World::World(const Config &config) +World::World(const Assets &assets, const Config &config) : blockType() , blockShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }}) , stairShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }}, { 0.0f, 0.0f }) , slabShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.0f, 0.5f }}) +, block_tex() , generate(config.gen) , chunks(config.load, blockType, generate) , player() @@ -26,8 +29,17 @@ World::World(const Config &config) BlockType::Faces slab_fill = { false, true, false, false, false, false }; BlockType::Faces stair_fill = { false, true, false, false, false, true }; + block_tex.Bind(); + block_tex.Reserve(16, 16, 4, Format()); + assets.LoadTexture("debug", block_tex, 0); + assets.LoadTexture("rock-1", block_tex, 1); + assets.LoadTexture("rock-2", block_tex, 2); + assets.LoadTexture("rock-3", block_tex, 3); + block_tex.FilterNearest(); + { // white block BlockType type(true, { 1.0f, 1.0f, 1.0f }, &blockShape); + type.texture = 1; type.label = "White Block"; type.block_light = true; type.collision = true; @@ -37,6 +49,7 @@ World::World(const Config &config) } { // white slab BlockType type(true, { 1.0f, 1.0f, 1.0f }, &slabShape); + type.texture = 1; type.label = "White Slab"; type.block_light = true; type.collision = true; @@ -46,6 +59,7 @@ World::World(const Config &config) } { // white stair BlockType type(true, { 1.0f, 1.0f, 1.0f }, &stairShape); + type.texture = 1; type.label = "White Stair"; type.block_light = true; type.collision = true; @@ -56,6 +70,7 @@ World::World(const Config &config) { // red block BlockType type(true, { 1.0f, 0.0f, 0.0f }, &blockShape); + type.texture = 3; type.label = "Red Block"; type.block_light = true; type.collision = true; @@ -65,6 +80,7 @@ World::World(const Config &config) } { // red slab BlockType type(true, { 1.0f, 0.0f, 0.0f }, &slabShape); + type.texture = 3; type.label = "Red Slab"; type.block_light = true; type.collision = true; @@ -74,6 +90,7 @@ World::World(const Config &config) } { // red stair BlockType type(true, { 1.0f, 0.0f, 0.0f }, &stairShape); + type.texture = 3; type.label = "Red Stair"; type.block_light = true; type.collision = true; @@ -84,6 +101,7 @@ World::World(const Config &config) { // green block BlockType type(true, { 0.0f, 1.0f, 0.0f }, &blockShape); + type.texture = 1; type.label = "Green Block"; type.block_light = true; type.collision = true; @@ -93,6 +111,7 @@ World::World(const Config &config) } { // green slab BlockType type(true, { 0.0f, 1.0f, 0.0f }, &slabShape); + type.texture = 1; type.label = "Green Slab"; type.block_light = true; type.collision = true; @@ -102,6 +121,7 @@ World::World(const Config &config) } { // green stair BlockType type(true, { 0.0f, 1.0f, 0.0f }, &stairShape); + type.texture = 1; type.label = "Green Stair"; type.block_light = true; type.collision = true; @@ -112,6 +132,7 @@ World::World(const Config &config) { // blue block BlockType type(true, { 0.0f, 0.0f, 1.0f }, &blockShape); + type.texture = 3; type.label = "Blue Block"; type.block_light = true; type.collision = true; @@ -121,6 +142,7 @@ World::World(const Config &config) } { // blue slab BlockType type(true, { 0.0f, 0.0f, 1.0f }, &slabShape); + type.texture = 3; type.label = "Blue Slab"; type.block_light = true; type.collision = true; @@ -130,6 +152,7 @@ World::World(const Config &config) } { // blue stair BlockType type(true, { 0.0f, 0.0f, 1.0f }, &stairShape); + type.texture = 3; type.label = "Blue Stair"; type.block_light = true; type.collision = true; @@ -140,6 +163,7 @@ World::World(const Config &config) { // glowing yellow block BlockType type(true, { 1.0f, 1.0f, 0.0f }, &blockShape); + type.texture = 2; type.label = "Light"; type.luminosity = 15; type.block_light = true; @@ -149,6 +173,18 @@ World::World(const Config &config) blockType.Add(type); } + { // the mysterious debug cube + BlockType type(true, { 1.0f, 1.0f, 1.0f }, &blockShape); + type.texture = 0; + type.label = "Debug Cube"; + type.luminosity = 0; + type.block_light = true; + type.collision = true; + type.collide_block = true; + type.fill = block_fill; + blockType.Add(type); + } + generate.Space(0); generate.Light(13); generate.Solids({ 1, 4, 7, 10 }); @@ -305,6 +341,7 @@ void World::Render(Viewport &viewport) { viewport.WorldPosition(player->Transform(player->ChunkCoords())); BlockLighting &chunk_prog = viewport.ChunkProgram(); + chunk_prog.SetTexture(block_tex); chunk_prog.SetFogDensity(fog_density); for (Chunk &chunk : chunks.Loaded()) { diff --git a/src/world/World.hpp b/src/world/World.hpp index b98efca..6bd8128 100644 --- a/src/world/World.hpp +++ b/src/world/World.hpp @@ -5,6 +5,7 @@ #include "ChunkLoader.hpp" #include "Entity.hpp" #include "Generator.hpp" +#include "../graphics/ArrayTexture.hpp" #include "../model/shapes.hpp" #include @@ -14,6 +15,7 @@ namespace blank { +class Assets; class Viewport; class WorldCollision; @@ -35,7 +37,7 @@ public: ChunkLoader::Config load = ChunkLoader::Config(); }; - explicit World(const Config &); + World(const Assets &, const Config &); bool Intersection( const Ray &, @@ -67,6 +69,8 @@ private: StairShape stairShape; CuboidShape slabShape; + ArrayTexture block_tex; + Generator generate; ChunkLoader chunks; diff --git a/src/world/block.cpp b/src/world/block.cpp index e06f3e0..aa91e79 100644 --- a/src/world/block.cpp +++ b/src/world/block.cpp @@ -75,6 +75,7 @@ std::ostream &operator <<(std::ostream &out, const Block::Turn &turn) { BlockType::BlockType(bool v, const glm::vec3 &col, const Shape *s) noexcept : shape(s) +, texture(0) , color(col) , outline_color(-1, -1, -1) , label("some block") @@ -93,7 +94,7 @@ void BlockType::FillEntityModel( const glm::mat4 &transform, EntityModel::Index idx_offset ) const noexcept { - shape->Vertices(buf.vertices, buf.normals, buf.indices, transform, idx_offset); + shape->Vertices(buf, transform, texture, idx_offset); buf.colors.insert(buf.colors.end(), shape->VertexCount(), color); } @@ -102,7 +103,7 @@ void BlockType::FillBlockModel( const glm::mat4 &transform, BlockModel::Index idx_offset ) const noexcept { - shape->Vertices(buf.vertices, buf.indices, transform, idx_offset); + shape->Vertices(buf, transform, texture, idx_offset); buf.colors.insert(buf.colors.end(), shape->VertexCount(), color); } @@ -111,7 +112,7 @@ void BlockType::FillOutlineModel( const glm::vec3 &pos_offset, OutlineModel::Index idx_offset ) const noexcept { - shape->Outline(buf.vertices, buf.indices, pos_offset, idx_offset); + shape->Outline(buf, pos_offset, idx_offset); buf.colors.insert(buf.colors.end(), shape->OutlineCount(), outline_color); }