X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fgraphics%2Frender.cpp;h=d1913ad3e77b18d3a20aa51c4d6af7326982827b;hb=d2f4c8720ae2326fac4203fa4984d835e875b355;hp=1a6d1abd80c124e7367969b863b84771ffc6b40b;hpb=50f35affb16c78bd3d0b420f5ba37d74fcac391f;p=blank.git diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 1a6d1ab..d1913ad 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -1,12 +1,16 @@ -#include "BlendedSprite.hpp" +#include "ArrayTexture.hpp" +#include "CubeMap.hpp" #include "Font.hpp" #include "Format.hpp" -#include "Text.hpp" #include "Texture.hpp" +#include "TextureBase.hpp" #include "Viewport.hpp" +#include "../app/init.hpp" + #include #include +#include #include #include @@ -102,8 +106,8 @@ bool Font::HasGlyph(Uint16 c) const noexcept { } -glm::tvec2 Font::TextSize(const char *text) const { - glm::tvec2 size; +glm::ivec2 Font::TextSize(const char *text) const { + glm::ivec2 size; if (TTF_SizeUTF8(handle, text, &size.x, &size.y) != 0) { throw std::runtime_error(TTF_GetError()); } @@ -127,8 +131,32 @@ void Font::Render(const char *text, Texture &tex) const { SDL_FreeSurface(srf); } - -void Format::ReadPixelFormat(const SDL_PixelFormat &fmt) { +Format::Format() noexcept +: 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) noexcept +: sdl_format(fmt) { if (fmt.BytesPerPixel == 4) { if (fmt.Amask == 0xFF) { if (fmt.Rmask == 0xFF00) { @@ -157,78 +185,59 @@ 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; +} -Text::Text() noexcept -: tex() -, sprite() -, bg(1.0f, 1.0f, 1.0f, 0.0f) -, fg(1.0f, 1.0f, 1.0f, 1.0f) -, size(0.0f) -, pos(0.0f) -, grav(Gravity::NORTH_WEST) -, pivot(Gravity::NORTH_WEST) -, dirty(false) -, visible(false) { +template +TextureBase::TextureBase() { + glGenTextures(COUNT, handle); } -void Text::Set(const Font &font, const char *text) { - font.Render(text, tex); - size = font.TextSize(text); - dirty = true; +template +TextureBase::~TextureBase() { + glDeleteTextures(COUNT, handle); } -void Text::Update() { - sprite.LoadRect(size.x, size.y, align(pivot, size)); - dirty = false; +template +TextureBase::TextureBase(TextureBase &&other) noexcept { + std::memcpy(handle, other.handle, sizeof(handle)); + std::memset(other.handle, 0, sizeof(handle)); } -void Text::Render(Viewport &viewport) noexcept { - if (dirty) { - Update(); - } - BlendedSprite &prog = viewport.SpriteProgram(); - viewport.SetCursor(pos, grav); - prog.SetM(viewport.Cursor()); - prog.SetTexture(tex); - prog.SetBG(bg); - prog.SetFG(fg); - sprite.Draw(); +template +TextureBase &TextureBase::operator =(TextureBase &&other) noexcept { + std::swap(handle, other.handle); + return *this; } Texture::Texture() -: handle(0) +: TextureBase() , width(0) , height(0) { - glGenTextures(1, &handle); + } Texture::~Texture() { - if (handle != 0) { - glDeleteTextures(1, &handle); - } + } Texture::Texture(Texture &&other) noexcept -: handle(other.handle) { - other.handle = 0; +: TextureBase(std::move(other)) { width = other.width; height = other.height; } Texture &Texture::operator =(Texture &&other) noexcept { - std::swap(handle, other.handle); + TextureBase::operator =(std::move(other)); width = other.width; height = other.height; return *this; } -void Texture::Bind() noexcept { - glBindTexture(GL_TEXTURE_2D, handle); -} - namespace { bool ispow2(unsigned int i) { // don't care about i == 0 here @@ -237,8 +246,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); @@ -254,8 +262,11 @@ void Texture::Data(const SDL_Surface &srf, bool pad2) noexcept { UnpackRowLength(0); } else if (srf.w > (1 << 30) || srf.h > (1 << 30)) { + // That's at least one gigapixel in either or both dimensions. + // If this is not an error, that's an insanely large or high + // resolution texture. #ifndef NDEBUG - throw std::runtime_error("texture too large"); + std::cerr << "texture size exceeds 2^30, aborting data import" << std::endl; #endif } else { GLsizei width = 1, height = 1; @@ -300,25 +311,6 @@ void Texture::Data(GLsizei w, GLsizei h, const Format &format, GLvoid *data) noe } -void Texture::FilterNearest() noexcept { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -} - -void Texture::FilterLinear() noexcept { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -} - -void Texture::FilterTrilinear() noexcept { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glGenerateMipmap(GL_TEXTURE_2D); -} - - void Texture::UnpackAlignment(GLint i) noexcept { glPixelStorei(GL_UNPACK_ALIGNMENT, i); } @@ -336,4 +328,140 @@ void Texture::UnpackRowLength(GLint i) noexcept { glPixelStorei(GL_UNPACK_ROW_LENGTH, i); } + +ArrayTexture::ArrayTexture() +: TextureBase() +, width(0) +, height(0) +, depth(0) { + +} + +ArrayTexture::~ArrayTexture() { + +} + +ArrayTexture::ArrayTexture(ArrayTexture &&other) noexcept +: TextureBase(std::move(other)) { + width = other.width; + height = other.height; + depth = other.depth; +} + +ArrayTexture &ArrayTexture::operator =(ArrayTexture &&other) noexcept { + TextureBase::operator =(std::move(other)); + width = other.width; + height = other.height; + depth = other.depth; + return *this; +} + + +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 + ); +} + + +CubeMap::CubeMap() +: TextureBase() { + +} + +CubeMap::~CubeMap() { + +} + +CubeMap::CubeMap(CubeMap &&other) noexcept +: TextureBase(std::move(other)) { + +} + +CubeMap &CubeMap::operator =(CubeMap &&other) noexcept { + TextureBase::operator =(std::move(other)); + return *this; +} + + +void CubeMap::Data(Face f, const SDL_Surface &srf) { + Format format; + Format fmt(*srf.format); + if (format.Compatible(fmt)) { + Data(f, srf.w, srf.h, 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(f, converted->w, converted->h, new_fmt, converted->pixels); + SDL_FreeSurface(converted); + } +} + +void CubeMap::Data(Face face, GLsizei w, GLsizei h, const Format &f, GLvoid *data) noexcept { + glTexImage2D( + face, // which + 0, // mipmap level + f.internal, // internal format + w, h, // size + 0, // border + f.format, f.type, // pixel format + data // pixel data + ); +} + }