Can now view different LODs of objects in object viewer; Object loads only the textures referenced by current LOD

This commit is contained in:
2015-05-27 14:03:23 +02:00
parent 1221f19b67
commit 584da2e3e8
6 changed files with 82 additions and 20 deletions

View File

@@ -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<render::Object>(renderer, obj, palt);
object_ = std::make_unique<render::Object>(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<render::Object>(renderer_, obj_, palt_, lod_);
}
} else {
if (lod_ > 0) {
--lod_;
object_ = std::make_unique<render::Object>(renderer_, obj_, palt_, lod_);
}
}
break;
}
break;
}

View File

@@ -21,6 +21,7 @@ namespace game {
bool handleEvent(SDL_Event& event) override;
private:
ObjDecoder& obj_;
PaletteDecoder& palt_;
std::unique_ptr<render::Object> object_;
unsigned delta_;
@@ -36,6 +37,7 @@ namespace game {
Direction rotatingUD_, rotatingRL_, moveRL_, moveFB_;
float rotUD_, rotRL_, posX_, posZ_;
unsigned lod_;
};
}

View File

@@ -1,3 +1,5 @@
#include <set>
#include <glbinding/gl/gl.h>
#include <glm/gtx/transform.hpp>
@@ -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<uint8_t> genMipmap(uint8_t const* src, unsigned srcWidth, unsigned srcHeight,
unsigned levels, bool colorize = false)
{
@@ -186,6 +197,7 @@ namespace render {
std::tuple<std::vector<TexAtlasInfo>, TextureResource>
genTexAtlas(ObjDecoder::Textures const& texs,
std::set<uint16_t> const& usedTexs,
PaletteDecoder::Palette const& palt)
{
// Build texture atlas for object
@@ -198,35 +210,56 @@ namespace render {
maxTex = 8192;
unsigned minSize = std::numeric_limits<unsigned>::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<unsigned>(minSize, std::min<unsigned>(tex.width, tex.height));
accumWidth += tex.width;
maxHeight = std::max<unsigned>(maxHeight, tex.height);
maxWidth = std::max<unsigned>(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<<minLg);
if (minPow2 < minSize) {
++minLg;
minPow2 <<= 1;
}
// if (minPow2 < 32) {
// minPow2 = 32;
// minLg = 5;
// }
printf("Minimum texture size %u, using %u alignment and %u mipmap levels\n",
minSize, minPow2, minLg);
// Try to get an aprox. square atlas
unsigned accumWidth2 = 1<<(ilog2(sqrt(accumWidth*maxHeight)));
unsigned maxWidth2 = 1u<<ilog2(maxWidth);
if (maxWidth2 < maxWidth)
maxWidth2 <<= 1;
accumWidth2 = std::min(std::max(maxWidth2, accumWidth2), maxTex);
printf("Squarified target width %u\n", accumWidth2);
std::vector<TexAtlasInfo> 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<uint8_t> 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<VertexAttribs>, std::vector<uint16_t> >
genVertexAttribs(ObjDecoder& obj, std::vector<TexAtlasInfo>& atlasInfo,
genVertexAttribs(ObjDecoder& obj, ObjDecoder::Triangles const& tris,
ObjDecoder::Quads const& quads, std::vector<TexAtlasInfo>& atlasInfo,
AnimTexInfo *animTex = nullptr)
{
auto tris = obj.getTriangles();
auto quads = obj.getQuads();
// Deduplicate vertex attributes, track indices
std::map<VertexAttribs, size_t> vertexAttribsMap;
std::vector<VertexAttribs> 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<uint16_t> 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<TexAtlasInfo> 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<int>(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<int>(GL_LINEAR_MIPMAP_LINEAR));
}
@@ -446,9 +490,9 @@ namespace render {
std::vector<VertexAttribs> vertexAttribs;
std::vector<uint16_t> 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());

View File

@@ -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;

View File

@@ -11,6 +11,8 @@ std::unique_ptr<render::VBOManager> Singleton<render::VBOManager>::instance{null
template<>
std::once_flag Singleton<render::VBOManager>::instance_flag{};
const size_t render::VBOManager::default_size = 1048576;
namespace render {
VBOManager::VBOManager()
{

View File

@@ -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;