X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fgraphics%2Frender.cpp;h=f0ead9ba78073f602d40bac8ffb6da04575ecf05;hb=c0a5ece0f6bacea1b85157a908d710070fb0affd;hp=2b227422a48cb3b950390d73cf152350fcf7f716;hpb=376fc1fca87fcdd22dabadf6d01d245ef8c3cedd;p=blank.git diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 2b22742..f0ead9b 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -1,11 +1,16 @@ -#include "BlendedSprite.hpp" +#include "ArrayTexture.hpp" +#include "CubeMap.hpp" #include "Font.hpp" #include "Format.hpp" #include "Texture.hpp" +#include "TextureBase.hpp" #include "Viewport.hpp" +#include "../app/error.hpp" + #include #include +#include #include #include @@ -15,7 +20,7 @@ namespace blank { Font::Font(const char *src, int size, long index) : handle(TTF_OpenFontIndex(src, size, index)) { if (!handle) { - throw std::runtime_error(TTF_GetError()); + throw TTFError("TTF_OpenFontIndex"); } } @@ -101,10 +106,10 @@ 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()); + throw TTFError("TTF_SizeUTF8"); } return size; } @@ -118,7 +123,7 @@ Texture Font::Render(const char *text) const { void Font::Render(const char *text, Texture &tex) const { SDL_Surface *srf = TTF_RenderUTF8_Blended(handle, text, { 0xFF, 0xFF, 0xFF, 0xFF }); if (!srf) { - throw std::runtime_error(TTF_GetError()); + throw TTFError("TTF_RenderUTF8_Blended"); } tex.Bind(); tex.Data(*srf, false); @@ -126,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) { @@ -156,39 +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; +} + + +template +TextureBase::TextureBase() { + glGenTextures(COUNT, handle); +} + +template +TextureBase::~TextureBase() { + glDeleteTextures(COUNT, handle); +} + +template +TextureBase::TextureBase(TextureBase &&other) noexcept { + std::memcpy(handle, other.handle, sizeof(handle)); + std::memset(other.handle, 0, sizeof(handle)); +} + +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 @@ -197,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); @@ -214,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; @@ -260,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); } @@ -296,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 + ); +} + }