From 584da2e3e8551724d770f63ba9ab8fff5c3f2753 Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Wed, 27 May 2015 14:03:23 +0200 Subject: [PATCH] Can now view different LODs of objects in object viewer; Object loads only the textures referenced by current LOD --- game/GSShowObject.cc | 20 ++++++++++-- game/GSShowObject.hh | 2 ++ render/Object.cc | 74 +++++++++++++++++++++++++++++++++++--------- render/Object.hh | 2 +- render/VBOManager.cc | 2 ++ render/VBOManager.hh | 2 +- 6 files changed, 82 insertions(+), 20 deletions(-) diff --git a/game/GSShowObject.cc b/game/GSShowObject.cc index 2aeaf73..93c8667 100644 --- a/game/GSShowObject.cc +++ b/game/GSShowObject.cc @@ -8,13 +8,14 @@ namespace game { GSShowObject::GSShowObject(render::Renderer& renderer, ObjDecoder& obj, PaletteDecoder& palt) - : GameState(renderer), obj_(obj), + : GameState(renderer), obj_(obj), palt_(palt), object_(nullptr), delta_(0), rotatingUD_(Direction::None), rotatingRL_(Direction::None), moveRL_(Direction::None), moveFB_(Direction::None), - rotUD_(0.0f), rotRL_(0.0f), posX_(0.0f), posZ_(0.0f) + rotUD_(0.0f), rotRL_(0.0f), posX_(0.0f), posZ_(0.0f), + lod_(0) { - object_ = std::make_unique(renderer, obj, palt); + object_ = std::make_unique(renderer, obj, palt, lod_); } GSShowObject::~GSShowObject() @@ -86,6 +87,19 @@ namespace game { if (moveRL_ == Direction::Right) moveRL_ = Direction::None; break; + case SDLK_l: + if (event.key.keysym.mod & KMOD_SHIFT) { + if (lod_+1 < obj_.getDetailLevels()) { + ++lod_; + object_ = std::make_unique(renderer_, obj_, palt_, lod_); + } + } else { + if (lod_ > 0) { + --lod_; + object_ = std::make_unique(renderer_, obj_, palt_, lod_); + } + } + break; } break; } diff --git a/game/GSShowObject.hh b/game/GSShowObject.hh index 8f35aaf..6c81f16 100644 --- a/game/GSShowObject.hh +++ b/game/GSShowObject.hh @@ -21,6 +21,7 @@ namespace game { bool handleEvent(SDL_Event& event) override; private: ObjDecoder& obj_; + PaletteDecoder& palt_; std::unique_ptr object_; unsigned delta_; @@ -36,6 +37,7 @@ namespace game { Direction rotatingUD_, rotatingRL_, moveRL_, moveFB_; float rotUD_, rotRL_, posX_, posZ_; + unsigned lod_; }; } diff --git a/render/Object.cc b/render/Object.cc index 10fcb64..4b3e6e8 100644 --- a/render/Object.cc +++ b/render/Object.cc @@ -1,3 +1,5 @@ +#include + #include #include @@ -46,6 +48,11 @@ namespace render { ObjDecoder::Texture const& tex; }; + /* Copy from paletted texture 'src' into BGRA texture 'dst' using palette 'palt' + Palette entry 0xff is transparent, all others are opaque. + For opaque pixels the color components are copied from a neighbouring + opaque pixel if available. + */ void copyPaletteTexture(uint8_t const* src, unsigned srcWidth, unsigned srcHeight, uint8_t *dst, unsigned dstStride, PaletteDecoder::Palette const& palt) @@ -108,6 +115,10 @@ namespace render { } } + /* Generate Mipmaps for BGRA texture 'src'. + The mipmapping algorithm computes the alpha-weighted average of the color + values, and the average of the alpha values, of a 2x2 block of pixels. + */ std::vector genMipmap(uint8_t const* src, unsigned srcWidth, unsigned srcHeight, unsigned levels, bool colorize = false) { @@ -186,6 +197,7 @@ namespace render { std::tuple, TextureResource> genTexAtlas(ObjDecoder::Textures const& texs, + std::set const& usedTexs, PaletteDecoder::Palette const& palt) { // Build texture atlas for object @@ -198,35 +210,56 @@ namespace render { maxTex = 8192; unsigned minSize = std::numeric_limits::max(); - unsigned accumWidth = 0, maxHeight = 0; + unsigned accumWidth = 0, maxHeight = 0, maxWidth = 0; + unsigned i = 0; for (auto& tex : texs) { + if (usedTexs.find(i++) == usedTexs.end()) + continue; + minSize = std::min(minSize, std::min(tex.width, tex.height)); accumWidth += tex.width; maxHeight = std::max(maxHeight, tex.height); + maxWidth = std::max(maxWidth, tex.width); + } + + // Set lower bound of minSize to ensure a minimum number of mipmap levels + minSize = std::max(minSize, 16u); + unsigned minLg = ilog2(minSize), minPow2 = (1< ret; - unsigned xpos = 0, ypos = 0, lineMaxHeight = 0, maxWidth = 0; + unsigned xpos = 0, ypos = 0, lineMaxHeight = 0; + maxWidth = 0; + i = 0; for (auto& tex : texs) { + if (usedTexs.find(i++) == usedTexs.end()) { + TexAtlasInfo info = {0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0.0f, tex}; + ret.push_back(info); + continue; + } + unsigned alignWidth = (tex.width%minPow2 == 0)?tex.width:tex.width+(minPow2-tex.width%minPow2); unsigned alignHeight = (tex.height%minPow2 == 0)?tex.height:tex.height+(minPow2-tex.height%minPow2); if (xpos + alignWidth > accumWidth2) { + if (alignWidth > maxTex) + throw Exception{"Cannot fit obj textures into GL texture"}; ypos += lineMaxHeight; maxWidth = std::max(maxWidth, xpos); lineMaxHeight = 0; @@ -249,6 +282,9 @@ namespace render { std::vector pixels(atlasWidth*atlasHeight*4); // Copy textures into atlas for (auto& info : ret) { + if (info.alignWidth == 0) + continue; + info.xofs = (info.x+0.5f)/atlasWidth; info.yofs = (info.y+0.5f)/atlasHeight; info.xscale = (info.tex.width-1.0f)/(atlasWidth*info.tex.width); @@ -325,12 +361,10 @@ namespace render { } std::tuple, std::vector > - genVertexAttribs(ObjDecoder& obj, std::vector& atlasInfo, + genVertexAttribs(ObjDecoder& obj, ObjDecoder::Triangles const& tris, + ObjDecoder::Quads const& quads, std::vector& atlasInfo, AnimTexInfo *animTex = nullptr) { - auto tris = obj.getTriangles(); - auto quads = obj.getQuads(); - // Deduplicate vertex attributes, track indices std::map vertexAttribsMap; std::vector vertexAttribs; @@ -420,24 +454,34 @@ namespace render { } - Object::Object(Renderer& renderer, ObjDecoder& obj, PaletteDecoder& palt) + Object::Object(Renderer& renderer, ObjDecoder& obj, PaletteDecoder& palt, unsigned lod) : TransformDrawable(renderer), vbo_(), rot_(0.0f), animFrame_(0) { // Acquire shader program_ = ProgramProvider::getInstance().getProgram("object", "object"); + + // Determine used textures + auto tris = obj.getTriangles(lod); + auto quads = obj.getQuads(lod); + std::set usedTexs; + + for (auto& tri: tris) + usedTexs.insert(tri.tex); + for (auto& quad: quads) + usedTexs.insert(quad.tex); // Generate texture atlas auto& texs = obj.getTextures(); std::vector atlasInfo; if (texs.size() > 0) { - std::tie(atlasInfo, tex_) = genTexAtlas(texs, palt.getPalette()); + std::tie(atlasInfo, tex_) = genTexAtlas(texs, usedTexs, palt.getPalette()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast(GL_LINEAR_MIPMAP_LINEAR)); } auto& texAnims = obj.getTextureAnimations(); AnimTexInfo animInfo; - if (texAnims.size() > 0) { + if ((usedTexs.find(atlasInfo.size()) != usedTexs.end()) && (texAnims.size() > 0)) { std::tie(animInfo, texAnim_) = genTexAnim(texAnims[0], palt.getPalette()); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, static_cast(GL_LINEAR_MIPMAP_LINEAR)); } @@ -446,9 +490,9 @@ namespace render { std::vector vertexAttribs; std::vector indices; if (texAnims.size() > 0) - std::tie(vertexAttribs, indices) = genVertexAttribs(obj, atlasInfo, &animInfo); + std::tie(vertexAttribs, indices) = genVertexAttribs(obj, tris, quads, atlasInfo, &animInfo); else - std::tie(vertexAttribs, indices) = genVertexAttribs(obj, atlasInfo); + std::tie(vertexAttribs, indices) = genVertexAttribs(obj, tris, quads, atlasInfo); // Setup GL vertex buffer and vertex array glGenVertexArrays(1, &vertexArray_.get()); diff --git a/render/Object.hh b/render/Object.hh index fb55666..e682192 100644 --- a/render/Object.hh +++ b/render/Object.hh @@ -14,7 +14,7 @@ class PaletteDecoder; namespace render { class Object : public TransformDrawable { public: - Object(Renderer& renderer, ObjDecoder& obj, PaletteDecoder& palt); + Object(Renderer& renderer, ObjDecoder& obj, PaletteDecoder& palt, unsigned lod = 0); void setAnimFrame(unsigned frame) { animFrame_ = frame; diff --git a/render/VBOManager.cc b/render/VBOManager.cc index 19c17f0..6234820 100644 --- a/render/VBOManager.cc +++ b/render/VBOManager.cc @@ -11,6 +11,8 @@ std::unique_ptr Singleton::instance{null template<> std::once_flag Singleton::instance_flag{}; +const size_t render::VBOManager::default_size = 1048576; + namespace render { VBOManager::VBOManager() { diff --git a/render/VBOManager.hh b/render/VBOManager.hh index 281b679..a87d55e 100644 --- a/render/VBOManager.hh +++ b/render/VBOManager.hh @@ -26,7 +26,7 @@ namespace render { class VBO; - static const size_t default_size = 1048576; + static const size_t default_size; static const size_t alignment = 4; static const gl::GLenum default_type = gl::GL_STATIC_DRAW;