]> git.localhorst.tv Git - blank.git/blobdiff - src/graphics/render.cpp
move common exceptions to app/error
[blank.git] / src / graphics / render.cpp
index 470cb191f4185ca893bdd683158b84e4042fbb15..f0ead9ba78073f602d40bac8ffb6da04575ecf05 100644 (file)
@@ -1,13 +1,16 @@
 #include "ArrayTexture.hpp"
+#include "CubeMap.hpp"
 #include "Font.hpp"
 #include "Format.hpp"
 #include "Texture.hpp"
+#include "TextureBase.hpp"
 #include "Viewport.hpp"
 
-#include "../app/init.hpp"
+#include "../app/error.hpp"
 
 #include <algorithm>
 #include <cstring>
+#include <iostream>
 #include <memory>
 #include <stdexcept>
 
@@ -17,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");
        }
 }
 
@@ -106,7 +109,7 @@ bool Font::HasGlyph(Uint16 c) const noexcept {
 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;
 }
@@ -120,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);
@@ -128,7 +131,7 @@ void Font::Render(const char *text, Texture &tex) const {
        SDL_FreeSurface(srf);
 }
 
-Format::Format()
+Format::Format() noexcept
 : format(GL_BGRA)
 , type(GL_UNSIGNED_INT_8_8_8_8_REV)
 , internal(GL_RGBA8) {
@@ -152,7 +155,7 @@ Format::Format()
        sdl_format.next = nullptr;
 }
 
-Format::Format(const SDL_PixelFormat &fmt)
+Format::Format(const SDL_PixelFormat &fmt) noexcept
 : sdl_format(fmt) {
        if (fmt.BytesPerPixel == 4) {
                if (fmt.Amask == 0xFF) {
@@ -187,38 +190,54 @@ bool Format::Compatible(const Format &other) const noexcept {
 }
 
 
+template<GLenum TARGET, GLsizei COUNT>
+TextureBase<TARGET, COUNT>::TextureBase() {
+       glGenTextures(COUNT, handle);
+}
+
+template<GLenum TARGET, GLsizei COUNT>
+TextureBase<TARGET, COUNT>::~TextureBase() {
+       glDeleteTextures(COUNT, handle);
+}
+
+template<GLenum TARGET, GLsizei COUNT>
+TextureBase<TARGET, COUNT>::TextureBase(TextureBase &&other) noexcept {
+       std::memcpy(handle, other.handle, sizeof(handle));
+       std::memset(other.handle, 0, sizeof(handle));
+}
+
+template<GLenum TARGET, GLsizei COUNT>
+TextureBase<TARGET, COUNT> &TextureBase<TARGET, COUNT>::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
@@ -243,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;
@@ -289,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);
 }
@@ -327,29 +330,26 @@ void Texture::UnpackRowLength(GLint i) noexcept {
 
 
 ArrayTexture::ArrayTexture()
-: handle(0)
+: TextureBase()
 , 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;
+: TextureBase(std::move(other)) {
        width = other.width;
        height = other.height;
        depth = other.depth;
 }
 
 ArrayTexture &ArrayTexture::operator =(ArrayTexture &&other) noexcept {
-       std::swap(handle, other.handle);
+       TextureBase::operator =(std::move(other));
        width = other.width;
        height = other.height;
        depth = other.depth;
@@ -357,11 +357,6 @@ ArrayTexture &ArrayTexture::operator =(ArrayTexture &&other) noexcept {
 }
 
 
-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
@@ -413,22 +408,60 @@ void ArrayTexture::Data(GLsizei l, const Format &f, GLvoid *data) noexcept {
 }
 
 
-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);
+CubeMap::CubeMap()
+: TextureBase() {
+
+}
+
+CubeMap::~CubeMap() {
+
+}
+
+CubeMap::CubeMap(CubeMap &&other) noexcept
+: TextureBase(std::move(other)) {
+
 }
 
-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);
+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<SDL_Surface *>(&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 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);
+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
+       );
 }
 
 }