Can now view different LODs of objects in object viewer; Object loads only the textures referenced by current LOD
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user