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 {
|
namespace game {
|
||||||
GSShowObject::GSShowObject(render::Renderer& renderer, ObjDecoder& obj,
|
GSShowObject::GSShowObject(render::Renderer& renderer, ObjDecoder& obj,
|
||||||
PaletteDecoder& palt)
|
PaletteDecoder& palt)
|
||||||
: GameState(renderer), obj_(obj),
|
: GameState(renderer), obj_(obj), palt_(palt),
|
||||||
object_(nullptr), delta_(0),
|
object_(nullptr), delta_(0),
|
||||||
rotatingUD_(Direction::None), rotatingRL_(Direction::None),
|
rotatingUD_(Direction::None), rotatingRL_(Direction::None),
|
||||||
moveRL_(Direction::None), moveFB_(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()
|
GSShowObject::~GSShowObject()
|
||||||
@@ -86,6 +87,19 @@ namespace game {
|
|||||||
if (moveRL_ == Direction::Right)
|
if (moveRL_ == Direction::Right)
|
||||||
moveRL_ = Direction::None;
|
moveRL_ = Direction::None;
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace game {
|
|||||||
bool handleEvent(SDL_Event& event) override;
|
bool handleEvent(SDL_Event& event) override;
|
||||||
private:
|
private:
|
||||||
ObjDecoder& obj_;
|
ObjDecoder& obj_;
|
||||||
|
PaletteDecoder& palt_;
|
||||||
std::unique_ptr<render::Object> object_;
|
std::unique_ptr<render::Object> object_;
|
||||||
unsigned delta_;
|
unsigned delta_;
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ namespace game {
|
|||||||
|
|
||||||
Direction rotatingUD_, rotatingRL_, moveRL_, moveFB_;
|
Direction rotatingUD_, rotatingRL_, moveRL_, moveFB_;
|
||||||
float rotUD_, rotRL_, posX_, posZ_;
|
float rotUD_, rotRL_, posX_, posZ_;
|
||||||
|
unsigned lod_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include <set>
|
||||||
|
|
||||||
#include <glbinding/gl/gl.h>
|
#include <glbinding/gl/gl.h>
|
||||||
|
|
||||||
#include <glm/gtx/transform.hpp>
|
#include <glm/gtx/transform.hpp>
|
||||||
@@ -46,6 +48,11 @@ namespace render {
|
|||||||
ObjDecoder::Texture const& tex;
|
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,
|
void copyPaletteTexture(uint8_t const* src, unsigned srcWidth, unsigned srcHeight,
|
||||||
uint8_t *dst, unsigned dstStride,
|
uint8_t *dst, unsigned dstStride,
|
||||||
PaletteDecoder::Palette const& palt)
|
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,
|
std::vector<uint8_t> genMipmap(uint8_t const* src, unsigned srcWidth, unsigned srcHeight,
|
||||||
unsigned levels, bool colorize = false)
|
unsigned levels, bool colorize = false)
|
||||||
{
|
{
|
||||||
@@ -186,6 +197,7 @@ namespace render {
|
|||||||
|
|
||||||
std::tuple<std::vector<TexAtlasInfo>, TextureResource>
|
std::tuple<std::vector<TexAtlasInfo>, TextureResource>
|
||||||
genTexAtlas(ObjDecoder::Textures const& texs,
|
genTexAtlas(ObjDecoder::Textures const& texs,
|
||||||
|
std::set<uint16_t> const& usedTexs,
|
||||||
PaletteDecoder::Palette const& palt)
|
PaletteDecoder::Palette const& palt)
|
||||||
{
|
{
|
||||||
// Build texture atlas for object
|
// Build texture atlas for object
|
||||||
@@ -198,35 +210,56 @@ namespace render {
|
|||||||
maxTex = 8192;
|
maxTex = 8192;
|
||||||
|
|
||||||
unsigned minSize = std::numeric_limits<unsigned>::max();
|
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) {
|
for (auto& tex : texs) {
|
||||||
|
if (usedTexs.find(i++) == usedTexs.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
minSize = std::min<unsigned>(minSize, std::min<unsigned>(tex.width, tex.height));
|
minSize = std::min<unsigned>(minSize, std::min<unsigned>(tex.width, tex.height));
|
||||||
accumWidth += tex.width;
|
accumWidth += tex.width;
|
||||||
maxHeight = std::max<unsigned>(maxHeight, tex.height);
|
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);
|
unsigned minLg = ilog2(minSize), minPow2 = (1<<minLg);
|
||||||
if (minPow2 < minSize) {
|
if (minPow2 < minSize) {
|
||||||
++minLg;
|
++minLg;
|
||||||
minPow2 <<= 1;
|
minPow2 <<= 1;
|
||||||
}
|
}
|
||||||
// if (minPow2 < 32) {
|
|
||||||
// minPow2 = 32;
|
|
||||||
// minLg = 5;
|
|
||||||
// }
|
|
||||||
printf("Minimum texture size %u, using %u alignment and %u mipmap levels\n",
|
printf("Minimum texture size %u, using %u alignment and %u mipmap levels\n",
|
||||||
minSize, minPow2, minLg);
|
minSize, minPow2, minLg);
|
||||||
|
|
||||||
// Try to get an aprox. square atlas
|
// Try to get an aprox. square atlas
|
||||||
unsigned accumWidth2 = 1<<(ilog2(sqrt(accumWidth*maxHeight)));
|
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);
|
printf("Squarified target width %u\n", accumWidth2);
|
||||||
|
|
||||||
std::vector<TexAtlasInfo> ret;
|
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) {
|
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 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);
|
unsigned alignHeight = (tex.height%minPow2 == 0)?tex.height:tex.height+(minPow2-tex.height%minPow2);
|
||||||
|
|
||||||
if (xpos + alignWidth > accumWidth2) {
|
if (xpos + alignWidth > accumWidth2) {
|
||||||
|
if (alignWidth > maxTex)
|
||||||
|
throw Exception{"Cannot fit obj textures into GL texture"};
|
||||||
ypos += lineMaxHeight;
|
ypos += lineMaxHeight;
|
||||||
maxWidth = std::max(maxWidth, xpos);
|
maxWidth = std::max(maxWidth, xpos);
|
||||||
lineMaxHeight = 0;
|
lineMaxHeight = 0;
|
||||||
@@ -249,6 +282,9 @@ namespace render {
|
|||||||
std::vector<uint8_t> pixels(atlasWidth*atlasHeight*4);
|
std::vector<uint8_t> pixels(atlasWidth*atlasHeight*4);
|
||||||
// Copy textures into atlas
|
// Copy textures into atlas
|
||||||
for (auto& info : ret) {
|
for (auto& info : ret) {
|
||||||
|
if (info.alignWidth == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
info.xofs = (info.x+0.5f)/atlasWidth;
|
info.xofs = (info.x+0.5f)/atlasWidth;
|
||||||
info.yofs = (info.y+0.5f)/atlasHeight;
|
info.yofs = (info.y+0.5f)/atlasHeight;
|
||||||
info.xscale = (info.tex.width-1.0f)/(atlasWidth*info.tex.width);
|
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> >
|
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)
|
AnimTexInfo *animTex = nullptr)
|
||||||
{
|
{
|
||||||
auto tris = obj.getTriangles();
|
|
||||||
auto quads = obj.getQuads();
|
|
||||||
|
|
||||||
// Deduplicate vertex attributes, track indices
|
// Deduplicate vertex attributes, track indices
|
||||||
std::map<VertexAttribs, size_t> vertexAttribsMap;
|
std::map<VertexAttribs, size_t> vertexAttribsMap;
|
||||||
std::vector<VertexAttribs> vertexAttribs;
|
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),
|
: TransformDrawable(renderer),
|
||||||
vbo_(), rot_(0.0f), animFrame_(0)
|
vbo_(), rot_(0.0f), animFrame_(0)
|
||||||
{
|
{
|
||||||
// Acquire shader
|
// Acquire shader
|
||||||
program_ = ProgramProvider::getInstance().getProgram("object", "object");
|
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
|
// Generate texture atlas
|
||||||
auto& texs = obj.getTextures();
|
auto& texs = obj.getTextures();
|
||||||
std::vector<TexAtlasInfo> atlasInfo;
|
std::vector<TexAtlasInfo> atlasInfo;
|
||||||
if (texs.size() > 0) {
|
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));
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast<int>(GL_LINEAR_MIPMAP_LINEAR));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& texAnims = obj.getTextureAnimations();
|
auto& texAnims = obj.getTextureAnimations();
|
||||||
AnimTexInfo animInfo;
|
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());
|
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));
|
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<VertexAttribs> vertexAttribs;
|
||||||
std::vector<uint16_t> indices;
|
std::vector<uint16_t> indices;
|
||||||
if (texAnims.size() > 0)
|
if (texAnims.size() > 0)
|
||||||
std::tie(vertexAttribs, indices) = genVertexAttribs(obj, atlasInfo, &animInfo);
|
std::tie(vertexAttribs, indices) = genVertexAttribs(obj, tris, quads, atlasInfo, &animInfo);
|
||||||
else
|
else
|
||||||
std::tie(vertexAttribs, indices) = genVertexAttribs(obj, atlasInfo);
|
std::tie(vertexAttribs, indices) = genVertexAttribs(obj, tris, quads, atlasInfo);
|
||||||
|
|
||||||
// Setup GL vertex buffer and vertex array
|
// Setup GL vertex buffer and vertex array
|
||||||
glGenVertexArrays(1, &vertexArray_.get());
|
glGenVertexArrays(1, &vertexArray_.get());
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class PaletteDecoder;
|
|||||||
namespace render {
|
namespace render {
|
||||||
class Object : public TransformDrawable {
|
class Object : public TransformDrawable {
|
||||||
public:
|
public:
|
||||||
Object(Renderer& renderer, ObjDecoder& obj, PaletteDecoder& palt);
|
Object(Renderer& renderer, ObjDecoder& obj, PaletteDecoder& palt, unsigned lod = 0);
|
||||||
|
|
||||||
void setAnimFrame(unsigned frame) {
|
void setAnimFrame(unsigned frame) {
|
||||||
animFrame_ = frame;
|
animFrame_ = frame;
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ std::unique_ptr<render::VBOManager> Singleton<render::VBOManager>::instance{null
|
|||||||
template<>
|
template<>
|
||||||
std::once_flag Singleton<render::VBOManager>::instance_flag{};
|
std::once_flag Singleton<render::VBOManager>::instance_flag{};
|
||||||
|
|
||||||
|
const size_t render::VBOManager::default_size = 1048576;
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
VBOManager::VBOManager()
|
VBOManager::VBOManager()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace render {
|
|||||||
|
|
||||||
class VBO;
|
class VBO;
|
||||||
|
|
||||||
static const size_t default_size = 1048576;
|
static const size_t default_size;
|
||||||
static const size_t alignment = 4;
|
static const size_t alignment = 4;
|
||||||
static const gl::GLenum default_type = gl::GL_STATIC_DRAW;
|
static const gl::GLenum default_type = gl::GL_STATIC_DRAW;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user