Add subimage to texture

This commit is contained in:
rexy712 2022-01-15 11:36:42 -08:00
parent 913285e57a
commit 1c4d5cd304
14 changed files with 399 additions and 102 deletions

View File

@ -23,13 +23,18 @@
namespace egn{ namespace egn{
//Represent a 3D point
using point = math::vec3<float>; using point = math::vec3<float>;
//Represent a line segment in 3D space given the end points
class line_segment class line_segment
{ {
public: public:
point point1; point point1;
point point2; point point2;
}; };
//Represent a 2D rectangle in 3D space given the four corners
class rectangle class rectangle
{ {
public: public:
@ -38,6 +43,8 @@ namespace egn{
point point3; point point3;
point point4; point point4;
}; };
//Axis aligned bounding box. Given the 2 opposite corners.
class aabb class aabb
{ {
public: public:
@ -52,6 +59,8 @@ namespace egn{
aabb& operator=(const aabb&) = default; aabb& operator=(const aabb&) = default;
aabb& operator=(aabb&&) = default; aabb& operator=(aabb&&) = default;
}; };
//3D sphere represented using a point and radius
class sphere class sphere
{ {
public: public:

View File

@ -25,6 +25,9 @@
namespace egn{ namespace egn{
//Virtual base for camera types
//Provides general object functionality as well as projection and view matrices.
//Derived classes must provide method of recalculating the projection matrix.
class camera_iface : public object_base class camera_iface : public object_base
{ {
protected: protected:
@ -41,16 +44,19 @@ namespace egn{
GLfloat m_far = 100; //far clipping plane in camera space GLfloat m_far = 100; //far clipping plane in camera space
public: public:
camera_iface() = default; camera_iface(void) = default;
//Initialize with given projection matrix and clipping planes
camera_iface(const math::mat4<GLfloat>& proj, GLfloat n, GLfloat f); camera_iface(const math::mat4<GLfloat>& proj, GLfloat n, GLfloat f);
camera_iface(const camera_iface&) = default; camera_iface(const camera_iface&) = default;
camera_iface(camera_iface&&) = default; camera_iface(camera_iface&&) = default;
virtual ~camera_iface() = default; virtual ~camera_iface(void) = default;
camera_iface& operator=(const camera_iface&) = default; camera_iface& operator=(const camera_iface&) = default;
camera_iface& operator=(camera_iface&&) = default; camera_iface& operator=(camera_iface&&) = default;
//Set the camera's location and update relevant data structures
void set_position(const math::vec3<GLfloat>& pos)override; void set_position(const math::vec3<GLfloat>& pos)override;
//Set the camera's facing angle and update relevant data structures
void set_orientation(const math::quaternion<GLfloat>& distance)override; void set_orientation(const math::quaternion<GLfloat>& distance)override;
//getters //getters
@ -62,18 +68,21 @@ namespace egn{
//setters //setters
void set_near_plane(GLfloat n); void set_near_plane(GLfloat n);
void set_far_plane(GLfloat f); void set_far_plane(GLfloat f);
//No control over matrices directly is done purposefully
protected: protected:
void recalc_view_matrix()const; void recalc_view_matrix()const;
virtual void recalc_projection_matrix()const = 0; virtual void recalc_projection_matrix()const = 0;
}; };
//Camera which performs an orthographic projection. Essentially camera will have no depth perspective
class ortho_camera : public camera_iface class ortho_camera : public camera_iface
{ {
protected: protected:
GLfloat m_width, m_height; //width and height of the camera space box GLfloat m_width, m_height; //width and height of the camera space box
public: public:
//Build camera with width, height, near, and far planes
ortho_camera(GLfloat w, GLfloat h, GLfloat n, GLfloat f); ortho_camera(GLfloat w, GLfloat h, GLfloat n, GLfloat f);
ortho_camera(const ortho_camera&) = default; ortho_camera(const ortho_camera&) = default;
ortho_camera(ortho_camera&&) = default; ortho_camera(ortho_camera&&) = default;
@ -82,9 +91,11 @@ namespace egn{
ortho_camera& operator=(const ortho_camera&) = default; ortho_camera& operator=(const ortho_camera&) = default;
ortho_camera& operator=(ortho_camera&&) = default; ortho_camera& operator=(ortho_camera&&) = default;
//Getters
GLfloat get_projection_width()const; GLfloat get_projection_width()const;
GLfloat get_projection_height()const; GLfloat get_projection_height()const;
//Setters
void set_projection_width(GLfloat w); void set_projection_width(GLfloat w);
void set_projection_height(GLfloat h); void set_projection_height(GLfloat h);
void set_projection_box(GLfloat w, GLfloat h); void set_projection_box(GLfloat w, GLfloat h);

View File

@ -23,17 +23,21 @@
namespace egn{ namespace egn{
//How far away before a collision is considered to have occurred
static constexpr float default_collision_epsilon = 1.0e-10f; static constexpr float default_collision_epsilon = 1.0e-10f;
class collidable_visitor; class collidable_visitor;
//Anything which derives from this is considered collidable and must be comparible to any other collidable
class collidable_iface class collidable_iface
{ {
public: public:
//Check if this and the other collidable have collided
virtual bool check_collision(const collidable_iface& c, float epsilon)const = 0; virtual bool check_collision(const collidable_iface& c, float epsilon)const = 0;
virtual void accept_visitor(collidable_visitor& v)const = 0; virtual void accept_visitor(collidable_visitor& v)const = 0;
}; };
//CRTP collidable to allow the collision checks to determine the concrete type of the collidable
template<typename Derived> template<typename Derived>
class collidable : public collidable_iface class collidable : public collidable_iface
{ {
@ -46,14 +50,23 @@ namespace egn{
namespace collision{ namespace collision{
//Basic collidable objects
//A 1D point
class point : public egn::point, public collidable<point> class point : public egn::point, public collidable<point>
{ {
public: public:
using egn::point::point; using egn::point::point;
using egn::point::operator=; using egn::point::operator=;
}; };
//A 2D line
class line_segment : public egn::line_segment, public collidable<line_segment>{}; class line_segment : public egn::line_segment, public collidable<line_segment>{};
//A 2D rectangle
class rectangle : public egn::rectangle, public collidable<rectangle>{}; class rectangle : public egn::rectangle, public collidable<rectangle>{};
//A 3D bounding box
class aabb : public egn::aabb, public collidable<aabb> class aabb : public egn::aabb, public collidable<aabb>
{ {
public: public:
@ -62,6 +75,8 @@ namespace egn{
aabb(const egn::aabb& b); aabb(const egn::aabb& b);
aabb& operator=(const egn::aabb& b); aabb& operator=(const egn::aabb& b);
}; };
//A 3D sphere
class sphere : public egn::sphere, public collidable<sphere> class sphere : public egn::sphere, public collidable<sphere>
{ {
public: public:
@ -73,6 +88,7 @@ namespace egn{
} }
//base class for collision visitor to provide polymorphic access to visitation functions
class collidable_visitor class collidable_visitor
{ {
public: public:
@ -83,6 +99,7 @@ namespace egn{
virtual void visit(const collision::point& p) = 0; virtual void visit(const collision::point& p) = 0;
}; };
//Templated visitor to allow checking collision from polymorphic types
template<typename T> template<typename T>
class collision_visitor : public collidable_visitor class collision_visitor : public collidable_visitor
{ {
@ -100,6 +117,7 @@ namespace egn{
constexpr bool result()const; constexpr bool result()const;
}; };
//Concrete collision detection that is eventually called
//bool check_collision(const collidable_iface& l, const collidable_iface& r, float epsilon = default_collision_epsilon); //bool check_collision(const collidable_iface& l, const collidable_iface& r, float epsilon = default_collision_epsilon);
bool check_collision(const aabb& l, const aabb& r, float epsilon = default_collision_epsilon); bool check_collision(const aabb& l, const aabb& r, float epsilon = default_collision_epsilon);
bool check_collision(const aabb& l, const sphere& r, float epsilon = default_collision_epsilon); bool check_collision(const aabb& l, const sphere& r, float epsilon = default_collision_epsilon);
@ -128,21 +146,23 @@ namespace egn{
bool check_collision(const point& l, const rectangle& r, float epsilon = default_collision_epsilon); bool check_collision(const point& l, const rectangle& r, float epsilon = default_collision_epsilon);
//Check collision between this and c via a visitor
template<typename Derived> template<typename Derived>
bool collidable<Derived>::check_collision(const collidable_iface& c, float epsilon)const{ bool collidable<Derived>::check_collision(const collidable_iface& c, float epsilon)const{
collision_visitor<Derived> vis(static_cast<const Derived&>(*this), epsilon); collision_visitor<Derived> vis(static_cast<const Derived&>(*this), epsilon); //Determine our true type for visitor
c.accept_visitor(vis); c.accept_visitor(vis); //have c give its true type to our visitor and check for collision
return vis.result(); return vis.result();
} }
template<typename Derived> template<typename Derived>
void collidable<Derived>::accept_visitor(collidable_visitor& v)const{ void collidable<Derived>::accept_visitor(collidable_visitor& v)const{
v.visit(static_cast<const Derived&>(*this)); v.visit(static_cast<const Derived&>(*this)); //Give the visitor our true type to allow calling correct collision check function
} }
template<typename T> template<typename T>
constexpr collision_visitor<T>::collision_visitor(const T& l, float epsilon): constexpr collision_visitor<T>::collision_visitor(const T& l, float epsilon):
m_l(l), m_l(l),
m_epsilon(epsilon){} m_epsilon(epsilon){}
//Call correct concrete function for given collision
template<typename T> template<typename T>
void collision_visitor<T>::visit(const collision::aabb& a){ void collision_visitor<T>::visit(const collision::aabb& a){
m_result = check_collision(m_l, a, m_epsilon); m_result = check_collision(m_l, a, m_epsilon);

77
include/engine/font.hpp Normal file
View File

@ -0,0 +1,77 @@
/**
This file is a part of our_dick
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OUR_DICK_ENGINE_FONT_HPP
#define OUR_DICK_ENGINE_FONT_HPP
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
#include <map>
#include <optional>
#include "graphics/texture.hpp"
#include "config.hpp"
namespace egn{
class font
{
private:
//ascii texture atlas
const char* m_bitmap_handle;
//When rendering unicode, load up new textures per code page to create many atlases
std::map<int, const char*> m_extra_codepages;
//stb or freetype font handle
public:
//load the font file and process it with stb/freetype lib
//render out basic ascii characters to bitmap texture atlas
//maybe do signed distance fonts? example: https://github.com/ShoYamanishi/SDFont
//dynamically add new codepage textures for rendering non-ascii
};
class font_generator
{
private:
static inline bool s_initialized = false;
static inline FT_Library s_ft;
private:
FT_Face m_face = nullptr;
public:
font_generator(const char* file);
~font_generator(void);
//params:
// start_codepoint: unicode character at which the atlas starts
// count: number of characters to make in the atlas
// glyph_width: requested pixel width of glyph
// glyph_height: requested pixel height of glyph
// atlas_width: requested pixel width of atlas
// atlas_height: requested pixel height of atlas
std::optional<gfx::texture> generate_atlas(int start_codepoint, int count, int glyph_width, int glyph_height, int atlas_width, int atlas_height);
std::optional<gfx::texture> generate_glyph(char character, int width, int height);
private:
static bool initialize_freetype_(void);
};
}
#endif

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of our_dick This file is a part of our_dick
Copyright (C) 2020 rexy712 Copyright (C) 2020-2022 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by it under the terms of the GNU Affero General Public License as published by
@ -29,6 +29,9 @@ namespace gfx{
public: public:
using texture::texture; using texture::texture;
using texture::operator=; using texture::operator=;
//tmp
material(texture&&);
}; };
} }

View File

@ -36,16 +36,16 @@ namespace gfx{
weak_texture_handle(const texture& tex); weak_texture_handle(const texture& tex);
weak_texture_handle(const weak_texture_handle&) = default; weak_texture_handle(const weak_texture_handle&) = default;
weak_texture_handle(weak_texture_handle&&) = default; weak_texture_handle(weak_texture_handle&&) = default;
~weak_texture_handle() = default; ~weak_texture_handle(void) = default;
weak_texture_handle& operator=(const weak_texture_handle&) = default; weak_texture_handle& operator=(const weak_texture_handle&) = default;
weak_texture_handle& operator=(weak_texture_handle&&) = default; weak_texture_handle& operator=(weak_texture_handle&&) = default;
GLuint raw()const; GLuint raw(void)const;
GLsizei get_width()const; GLsizei get_width(void)const;
GLsizei get_height()const; GLsizei get_height(void)const;
void bind()const; void bind(void)const;
void bind_unit(GLuint tunit)const; void bind_unit(GLuint tunit)const;
}; };
@ -81,29 +81,35 @@ namespace gfx{
GLsizei m_height = 0; GLsizei m_height = 0;
GLenum m_format = 0; GLenum m_format = 0;
GLenum m_type = GL_UNSIGNED_BYTE; GLenum m_type = GL_UNSIGNED_BYTE;
bool m_mipmapped = true;
public: public:
//create the texture with no image data //create the texture with no image data
texture(); texture(void);
texture(const unsigned char* data, GLenum format, GLsizei w, GLsizei h, GLenum type); texture(const unsigned char* data, GLenum format, GLsizei w, GLsizei h, GLenum type, bool mipmap = true);
texture(GLenum format, GLsizei w, GLsizei h, GLenum type); texture(GLenum format, GLsizei w, GLsizei h, GLenum type, bool mipmap = true);
//create the texture with image data from 'i' //create the texture with image data from 'i'
texture(const egn::image& i); texture(const egn::image& i, bool mipmap = true);
texture(const egn::deferred_image& i); texture(const egn::deferred_image& i, bool mipmap = true);
texture(const texture&) = delete; texture(const texture&);
texture(texture&&); texture(texture&&);
~texture(); ~texture(void);
texture& operator=(const texture&) = delete; texture& operator=(const texture&);
texture& operator=(texture&&); texture& operator=(texture&&);
GLuint raw()const; GLuint raw(void)const;
//overwrite the current image data with 'i' //overwrite the current image data with 'i'
bool set_image(const unsigned char* data, GLenum format, GLsizei w, GLsizei h, GLenum type); bool set_image(const unsigned char* data, GLenum format, GLsizei w, GLsizei h, GLenum type);
bool set_image(const egn::image& i); bool set_image(const egn::image& i);
bool set_image(const egn::deferred_image& i); bool set_image(const egn::deferred_image& i);
bool set_subimage(const unsigned char* data, GLenum format, GLenum type,
GLsizei xoffset, GLsizei yoffset, GLsizei w, GLsizei h);
bool set_subimage(const egn::image& i, GLsizei xoffset, GLsizei yoffset);
bool set_subimage(const egn::deferred_image& i, GLsizei xoffset, GLsizei yoffset);
//change wrap mode for both x and y //change wrap mode for both x and y
void set_wrap_mode(wrap w); void set_wrap_mode(wrap w);
void set_wrap_mode(wrap w, wrap h); void set_wrap_mode(wrap w, wrap h);
@ -116,25 +122,31 @@ namespace gfx{
void set_mag_filter(magfilter m); void set_mag_filter(magfilter m);
void set_min_filter(minfilter m); void set_min_filter(minfilter m);
magfilter get_mag_filter()const; magfilter get_mag_filter(void)const;
minfilter get_min_filter()const; minfilter get_min_filter(void)const;
math::vec4<GLfloat> get_border_color()const; math::vec4<GLfloat> get_border_color(void)const;
wrap get_wrap_x()const; wrap get_wrap_x(void)const;
wrap get_wrap_y()const; wrap get_wrap_y(void)const;
GLsizei get_width()const; GLsizei get_width(void)const;
GLsizei get_height()const; GLsizei get_height(void)const;
void enable_auto_mipmap(bool enable);
void generate_mipmap(void);
//release ownership of this texture object //release ownership of this texture object
GLuint release(); GLuint release(void);
//bind to GL_TEXTURE_2D //bind to GL_TEXTURE_2D
void bind()const; void bind(void)const;
//bind to given texture unit and load into given program uniform location //bind to given texture unit and load into given program uniform location
void bind_unit(GLuint tunit)const; void bind_unit(GLuint tunit)const;
weak_texture_handle create_handle()const; weak_texture_handle create_handle(void)const;
private:
bool create_texture_storage_(void);
}; };
} }

View File

@ -44,6 +44,7 @@ private:
}; };
private: private:
basic_framebuffer m_fb; basic_framebuffer m_fb;
gfx::fbo m_primary_fb;
gfx::shader_program* m_sprite_shader; gfx::shader_program* m_sprite_shader;
gfx::shader_program* m_screen_shader; gfx::shader_program* m_screen_shader;
gfx::vbo m_vbo; gfx::vbo m_vbo;

View File

@ -26,7 +26,7 @@ DEPDIR::=$(OBJDIR)/dep
LIBDIRS::=lib LIBDIRS::=lib
INCLUDE_DIRS::=include INCLUDE_DIRS::=include
CFLAGS::=-std=c18 -Wall -pedantic -Wextra CFLAGS::=-std=c18 -Wall -pedantic -Wextra
CXXFLAGS::=-std=c++20 -Wall -pedantic -Wextra -fno-rtti -fno-exceptions CXXFLAGS::=-std=c++20 -Wall -pedantic -Wextra -fno-rtti -fno-exceptions $(shell pkg-config --cflags freetype2)
DEBUG_CFLAGS::= DEBUG_CFLAGS::=
DEBUG_CXXFLAGS::=-DOUR_DICK_DEBUG=2 DEBUG_CXXFLAGS::=-DOUR_DICK_DEBUG=2
EXT::=cpp EXT::=cpp
@ -41,7 +41,7 @@ ifneq ($(WINDOWS),1)
#*nix settings #*nix settings
CC::=gcc CC::=gcc
CXX::=g++ CXX::=g++
LDLIBS::=-lglfw -lglad -ldl -lm -lportaudio -lsndfile -lpthread -lrexy LDLIBS::=-lglfw -lglad -ldl -lm -lportaudio -lsndfile -lpthread -lrexy $(shell pkg-config --libs freetype2)
ifeq ($(shell uname -s),Linux) ifeq ($(shell uname -s),Linux)
LDLIBS+=-lasound LDLIBS+=-lasound
endif endif

View File

@ -20,7 +20,7 @@
#include "math/mat.hpp" #include "math/mat.hpp"
#include "graphics/gl_include.hpp" //GLfloat #include "graphics/gl_include.hpp" //GLfloat
#include "engine/font.hpp"
gfx::unified_mesh square_mesh(const gfx::material& blank, const gfx::material& o, const gfx::material& x){ gfx::unified_mesh square_mesh(const gfx::material& blank, const gfx::material& o, const gfx::material& x){
static constexpr gfx::vertex s_vertices[] = { static constexpr gfx::vertex s_vertices[] = {
@ -64,7 +64,6 @@ board::board(egn::resource_manager& resman):
blank = resman.emplace_material("assets/images/blank.jpg", egn::deferred_image("assets/images/blank.jpg", true)).first; blank = resman.emplace_material("assets/images/blank.jpg", egn::deferred_image("assets/images/blank.jpg", true)).first;
o = resman.emplace_material("assets/images/o.jpg", egn::deferred_image("assets/images/o.jpg", true)).first; o = resman.emplace_material("assets/images/o.jpg", egn::deferred_image("assets/images/o.jpg", true)).first;
x = resman.emplace_material("assets/images/x.jpg", egn::deferred_image("assets/images/x.jpg", true)).first; x = resman.emplace_material("assets/images/x.jpg", egn::deferred_image("assets/images/x.jpg", true)).first;
x = resman.emplace_material("assets/images/x.jpg", egn::deferred_image("assets/images/x.jpg", true)).first;
if(!resman.has_model("square")){ if(!resman.has_model("square")){
sq = resman.emplace_model("square", square_mesh(*blank, *o, *x)).first; sq = resman.emplace_model("square", square_mesh(*blank, *o, *x)).first;

55
src/engine/font.cpp Normal file
View File

@ -0,0 +1,55 @@
/**
This file is a part of our_dick
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "engine/font.hpp"
namespace egn{
font_generator::font_generator(const char* file){
initialize_freetype_();
if(FT_New_Face(s_ft, file, 0, &m_face)){
debug_print_error("Failed to initialize font '%s'\n", file);
}
}
font_generator::~font_generator(void){
FT_Done_Face(m_face);
}
std::optional<gfx::texture> font_generator::generate_glyph(char character, int width, int height){
FT_Set_Pixel_Sizes(m_face, width, height);
if(FT_Load_Char(m_face, character, FT_LOAD_RENDER)){
debug_print_error("Failed to load character '%c', from font '%s'\n", character, m_face->family_name);
return {};
}
auto& bitmap = m_face->glyph->bitmap;
return {gfx::texture(bitmap.buffer, GL_RED, bitmap.width, bitmap.rows, GL_UNSIGNED_BYTE)};
}
bool font_generator::initialize_freetype_(void){
if(!s_initialized){
if(FT_Init_FreeType(&s_ft)){
return false;
}
return (s_initialized = true);
}
return true;
}
}

28
src/graphics/material.cpp Normal file
View File

@ -0,0 +1,28 @@
/**
This file is a part of our_dick
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "graphics/material.hpp"
#include <utility> //move
namespace gfx{
material::material(texture&& t):
texture(std::move(t)){}
}

View File

@ -20,6 +20,7 @@
#include "config.hpp" #include "config.hpp"
#include <utility> //exchange, swap #include <utility> //exchange, swap
#include <rexy/utility.hpp>
namespace gfx{ namespace gfx{
@ -65,62 +66,88 @@ namespace gfx{
}; };
return 1; return 1;
} }
[[maybe_unused]]
static GLint save_unpack_alignment_(void){
int old_alignment;
glGetIntegerv(GL_UNPACK_ALIGNMENT, &old_alignment);
return old_alignment;
}
texture::texture(void){
texture::texture(){
glCreateTextures(GL_TEXTURE_2D, 1, &m_tex_id); glCreateTextures(GL_TEXTURE_2D, 1, &m_tex_id);
} }
texture::texture(const unsigned char* data, GLenum format, GLsizei w, GLsizei h, GLenum type): texture::texture(const unsigned char* data, GLenum format, GLsizei w, GLsizei h, GLenum type, bool mipmap):
m_width(w), m_height(h), m_width(w), m_height(h),
m_format(format), m_type(type) m_format(format), m_type(type),
m_mipmapped(mipmap)
{ {
glCreateTextures(GL_TEXTURE_2D, 1, &m_tex_id); glCreateTextures(GL_TEXTURE_2D, 1, &m_tex_id);
switch(m_format){ GLint old_alignment = save_unpack_alignment_();
case GL_RED:
glTextureStorage2D(m_tex_id, 1, GL_R8, m_width, m_height); if(!create_texture_storage_()){
break; debug_print_error("Failed to create texture storage\n");
case GL_RG: return;
glTextureStorage2D(m_tex_id, 1, GL_RG8, m_width, m_height); }
break;
case GL_RGB:
glTextureStorage2D(m_tex_id, 1, GL_RGB8, m_width, m_height);
break;
case GL_RGBA:
glTextureStorage2D(m_tex_id, 1, GL_RGBA8, m_width, m_height);
break;
default:
debug_print_error("Unsupported format passed to texture constructor\n");
glDeleteTextures(1, &m_tex_id);
m_tex_id = 0;
return;
};
glTextureSubImage2D(m_tex_id, 0, 0, 0, m_width, m_height, m_format, m_type, data); glTextureSubImage2D(m_tex_id, 0, 0, 0, m_width, m_height, m_format, m_type, data);
glGenerateTextureMipmap(m_tex_id); if(m_mipmapped)
generate_mipmap();
glPixelStorei(GL_UNPACK_ALIGNMENT, old_alignment);
} }
texture::texture(GLenum format, GLsizei w, GLsizei h, GLenum type): texture::texture(GLenum format, GLsizei w, GLsizei h, GLenum type, bool mipmap):
texture(nullptr, format, w, h, type){} texture(nullptr, format, w, h, type, mipmap){}
texture::texture(const egn::image& i): texture::texture(const egn::image& i, bool mipmap):
texture() texture()
{ {
m_mipmapped = mipmap;
set_image(i); set_image(i);
} }
texture::texture(const egn::deferred_image& i): texture::texture(const egn::deferred_image& i, bool mipmap):
texture() texture()
{ {
m_mipmapped = mipmap;
set_image(i); set_image(i);
} }
texture::texture(const texture& t):
m_width(t.m_width), m_height(t.m_height),
m_format(t.m_format), m_type(t.m_type),
m_mipmapped(t.m_mipmapped)
{
//Copying textures is not preferable so generate a debug warning
debug_print_warn("Copy constructing texture!\n");
glCreateTextures(GL_TEXTURE_2D, 1, &m_tex_id);
GLint old_alignment = save_unpack_alignment_();
if(!create_texture_storage_()){
debug_print_error("Failed to create texture storage\n");
return;
}
glCopyImageSubData(t.m_tex_id, GL_TEXTURE_2D, 0, 0, 0, 0,
m_tex_id, GL_TEXTURE_2D, 0, 0, 0, 0,
m_width, m_height, 1);
if(m_mipmapped)
generate_mipmap();
glPixelStorei(GL_UNPACK_ALIGNMENT, old_alignment);
}
texture::texture(texture&& t): texture::texture(texture&& t):
m_tex_id(std::exchange(t.m_tex_id, 0)){} m_tex_id(std::exchange(t.m_tex_id, 0)),
texture::~texture(){ m_width(t.m_width), m_height(t.m_height),
m_format(t.m_format), m_type(t.m_type){}
texture::~texture(void){
glDeleteTextures(1, &m_tex_id); glDeleteTextures(1, &m_tex_id);
} }
texture& texture::operator=(const texture& t){
debug_print_warn("Copy assigning texture!\n");
return (*this = texture(t));
}
texture& texture::operator=(texture&& t){ texture& texture::operator=(texture&& t){
std::swap(m_tex_id, t.m_tex_id); std::swap(m_tex_id, t.m_tex_id);
return *this; return *this;
} }
GLuint texture::raw()const{ GLuint texture::raw(void)const{
return m_tex_id; return m_tex_id;
} }
@ -129,6 +156,8 @@ namespace gfx{
debug_print_error("Image is invalid\n"); debug_print_error("Image is invalid\n");
return false; return false;
} }
GLint old_alignment = save_unpack_alignment_();
if(m_width != w || m_height != h || m_format != format){ if(m_width != w || m_height != h || m_format != format){
if(m_format != 0){ if(m_format != 0){
debug_print_warn("Regenerating texture\n"); debug_print_warn("Regenerating texture\n");
@ -137,27 +166,17 @@ namespace gfx{
} }
m_width = w; m_width = w;
m_height = h; m_height = h;
switch(format){
case GL_RED:
glTextureStorage2D(m_tex_id, 1, GL_R8, m_width, m_height);
break;
case GL_RG:
glTextureStorage2D(m_tex_id, 1, GL_RG8, m_width, m_height);
break;
case GL_RGB:
glTextureStorage2D(m_tex_id, 1, GL_RGB8, m_width, m_height);
break;
case GL_RGBA:
glTextureStorage2D(m_tex_id, 1, GL_RGBA8, m_width, m_height);
break;
default:
debug_print_error("Invalid format for texture\n");
return false;
};
m_format = format; m_format = format;
if(!create_texture_storage_()){
debug_print_error("Invalid format for texture\n");
return false;
}
} }
glTextureSubImage2D(m_tex_id, 0, 0, 0, m_width, m_height, m_format, type, data); glTextureSubImage2D(m_tex_id, 0, 0, 0, m_width, m_height, m_format, type, data);
glGenerateTextureMipmap(m_tex_id); if(m_mipmapped)
generate_mipmap();
glPixelStorei(GL_UNPACK_ALIGNMENT, old_alignment);
return true; return true;
} }
bool texture::set_image(const egn::image& i){ bool texture::set_image(const egn::image& i){
@ -167,6 +186,37 @@ namespace gfx{
return set_image(i.get_image()); return set_image(i.get_image());
} }
bool texture::set_subimage(const unsigned char* data, GLenum format, GLenum type,
GLsizei xoffset, GLsizei yoffset, GLsizei w, GLsizei h)
{
if(!data){
debug_print_error("Image is invalid\n");
return false;
}
if(yoffset >= m_height || xoffset >= m_width){
debug_print_error("Texture is smaller than requested offsets: (%d, %d)\n", xoffset, yoffset);
return false;
}
GLint old_alignment = save_unpack_alignment_();
h = rexy::min(h, m_height - yoffset);
w = rexy::min(w, m_width - xoffset);
glTextureSubImage2D(m_tex_id, 0, xoffset, yoffset, w, h, format, type, data);
generate_mipmap();
glPixelStorei(GL_UNPACK_ALIGNMENT, old_alignment);
return true;
}
bool texture::set_subimage(const egn::image& i, GLsizei xoffset, GLsizei yoffset){
return set_subimage(i.data(), convert_channel_to_format(i.get_channels()), GL_UNSIGNED_BYTE, xoffset, yoffset, i.get_width(), i.get_height());
}
bool texture::set_subimage(const egn::deferred_image& i, GLsizei xoffset, GLsizei yoffset){
return set_subimage(i.get_image(), xoffset, yoffset);
}
void texture::set_wrap_mode(wrap w){ void texture::set_wrap_mode(wrap w){
glTextureParameteri(m_tex_id, GL_TEXTURE_WRAP_S, static_cast<GLint>(w)); glTextureParameteri(m_tex_id, GL_TEXTURE_WRAP_S, static_cast<GLint>(w));
glTextureParameteri(m_tex_id, GL_TEXTURE_WRAP_T, static_cast<GLint>(w)); glTextureParameteri(m_tex_id, GL_TEXTURE_WRAP_T, static_cast<GLint>(w));
@ -196,67 +246,99 @@ namespace gfx{
void texture::set_min_filter(minfilter m){ void texture::set_min_filter(minfilter m){
glTextureParameteri(m_tex_id, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(m)); glTextureParameteri(m_tex_id, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(m));
} }
auto texture::get_mag_filter()const -> magfilter{ auto texture::get_mag_filter(void)const -> magfilter{
GLint filter; GLint filter;
glGetTextureParameteriv(m_tex_id, GL_TEXTURE_MAG_FILTER, &filter); glGetTextureParameteriv(m_tex_id, GL_TEXTURE_MAG_FILTER, &filter);
return static_cast<magfilter>(filter); return static_cast<magfilter>(filter);
} }
auto texture::get_min_filter()const -> minfilter{ auto texture::get_min_filter(void)const -> minfilter{
GLint filter; GLint filter;
glGetTextureParameteriv(m_tex_id, GL_TEXTURE_MIN_FILTER, &filter); glGetTextureParameteriv(m_tex_id, GL_TEXTURE_MIN_FILTER, &filter);
return static_cast<minfilter>(filter); return static_cast<minfilter>(filter);
} }
math::vec4<GLfloat> texture::get_border_color()const{ math::vec4<GLfloat> texture::get_border_color(void)const{
math::vec4<GLfloat> color; math::vec4<GLfloat> color;
glGetTextureParameterfv(m_tex_id, GL_TEXTURE_BORDER_COLOR, color); glGetTextureParameterfv(m_tex_id, GL_TEXTURE_BORDER_COLOR, color);
return color; return color;
} }
auto texture::get_wrap_x()const -> wrap{ auto texture::get_wrap_x(void)const -> wrap{
GLint w; GLint w;
glGetTextureParameteriv(m_tex_id, GL_TEXTURE_WRAP_S, &w); glGetTextureParameteriv(m_tex_id, GL_TEXTURE_WRAP_S, &w);
return static_cast<wrap>(w); return static_cast<wrap>(w);
} }
auto texture::get_wrap_y()const -> wrap{ auto texture::get_wrap_y(void)const -> wrap{
GLint w; GLint w;
glGetTextureParameteriv(m_tex_id, GL_TEXTURE_WRAP_T, &w); glGetTextureParameteriv(m_tex_id, GL_TEXTURE_WRAP_T, &w);
return static_cast<wrap>(w); return static_cast<wrap>(w);
} }
GLsizei texture::get_width()const{ GLsizei texture::get_width(void)const{
return m_width; return m_width;
} }
GLsizei texture::get_height()const{ GLsizei texture::get_height(void)const{
return m_height; return m_height;
} }
GLuint texture::release(){ void texture::enable_auto_mipmap(bool enable){
m_mipmapped = enable;
}
void texture::generate_mipmap(void){
glGenerateTextureMipmap(m_tex_id);
}
GLuint texture::release(void){
return std::exchange(m_tex_id, 0); return std::exchange(m_tex_id, 0);
} }
void texture::bind()const{ void texture::bind(void)const{
glBindTexture(GL_TEXTURE_2D, m_tex_id); glBindTexture(GL_TEXTURE_2D, m_tex_id);
} }
void texture::bind_unit(GLuint tunit)const{ void texture::bind_unit(GLuint tunit)const{
glBindTextureUnit(tunit, m_tex_id); glBindTextureUnit(tunit, m_tex_id);
} }
weak_texture_handle texture::create_handle()const{ weak_texture_handle texture::create_handle(void)const{
return weak_texture_handle(*this); return weak_texture_handle(*this);
} }
bool texture::create_texture_storage_(void){
switch(m_format){
case GL_RED:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTextureStorage2D(m_tex_id, 1, GL_R8, m_width, m_height);
break;
case GL_RG:
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
glTextureStorage2D(m_tex_id, 1, GL_RG8, m_width, m_height);
break;
case GL_RGB:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTextureStorage2D(m_tex_id, 1, GL_RGB8, m_width, m_height);
break;
case GL_RGBA:
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTextureStorage2D(m_tex_id, 1, GL_RGBA8, m_width, m_height);
break;
default:
glDeleteTextures(1, &m_tex_id);
m_tex_id = 0;
return false;
};
return true;
}
weak_texture_handle::weak_texture_handle(const texture& tex): weak_texture_handle::weak_texture_handle(const texture& tex):
m_texture(&tex){} m_texture(&tex){}
GLuint weak_texture_handle::raw()const{ GLuint weak_texture_handle::raw(void)const{
return m_texture->raw(); return m_texture->raw();
} }
GLsizei weak_texture_handle::get_width()const{ GLsizei weak_texture_handle::get_width(void)const{
return m_texture->get_width(); return m_texture->get_width();
} }
GLsizei weak_texture_handle::get_height()const{ GLsizei weak_texture_handle::get_height(void)const{
return m_texture->get_height(); return m_texture->get_height();
} }
void weak_texture_handle::bind()const{ void weak_texture_handle::bind(void)const{
m_texture->bind(); m_texture->bind();
} }
void weak_texture_handle::bind_unit(GLuint tunit)const{ void weak_texture_handle::bind_unit(GLuint tunit)const{

View File

@ -25,6 +25,7 @@
#include "config.hpp" #include "config.hpp"
#include "tic_tac_toe.hpp" #include "tic_tac_toe.hpp"
#include "engine/font.hpp"
int main(){ int main(){
srand(time(NULL)); srand(time(NULL));

View File

@ -28,6 +28,7 @@
main_renderer::main_renderer(egn::resource_manager& res, int width, int height): main_renderer::main_renderer(egn::resource_manager& res, int width, int height):
m_fb(MAX_WIDTH, MAX_HEIGHT), m_fb(MAX_WIDTH, MAX_HEIGHT),
m_primary_fb(util::no_initialize),
m_vbo(s_vertices, sizeof(s_vertices), gfx::vbo::usage::DYNAMIC_DRAW) m_vbo(s_vertices, sizeof(s_vertices), gfx::vbo::usage::DYNAMIC_DRAW)
{ {
if(res.has_shader("sprite_shader")) if(res.has_shader("sprite_shader"))
@ -61,7 +62,6 @@ void main_renderer::set_vp_matrix(const math::mat4<GLfloat>& vp){
m_sprite_shader->set_uniform("vp_mat", vp); m_sprite_shader->set_uniform("vp_mat", vp);
} }
void main_renderer::render(scene& s){ void main_renderer::render(scene& s){
const auto& vp = m_fb.get_viewport();
m_fb.bind(); m_fb.bind();
m_fb.clear_color_buffer(); m_fb.clear_color_buffer();
m_fb.clear_depth_buffer(); m_fb.clear_depth_buffer();
@ -73,10 +73,9 @@ void main_renderer::render(scene& s){
(*it)->render(*m_sprite_shader); (*it)->render(*m_sprite_shader);
} }
glBindFramebuffer(GL_FRAMEBUFFER, 0); m_primary_fb.bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); m_primary_fb.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glViewport(0, 0, vp.z(), vp.w());
m_screen_shader->use(); m_screen_shader->use();
m_screen_shader->set_uniform("texture1", m_fb.colorbuffer(), 0); m_screen_shader->set_uniform("texture1", m_fb.colorbuffer(), 0);