More work on REAL 3D object decode/render; Some OpenGL stuff

This commit is contained in:
2015-05-03 20:12:05 +02:00
parent b780ff7f45
commit c11b0f7a09
21 changed files with 445 additions and 113 deletions

BIN
DejaVuSans.ttf Normal file

Binary file not shown.

View File

@@ -15,10 +15,10 @@ font2png_CXXSRCS ::= font2png.cc
font2png_LIBS ::= -lpng
mvedecode_CXXSRCS ::= mvedecode.cc TreFile.cc IffFile.cc util.cc MveDecoder.cc exceptions.cc decompress.cc $(render_CXXSRCS) $(game_CXXSRCS)
mvedecode_LIBS ::= -lSDL2 -lglbinding
mvedecode_LIBS ::= -lSDL2 -lSDL2_ttf -lglbinding
objdecode_CXXSRCS ::= objdecode.cc TreFile.cc IffFile.cc util.cc ObjDecoder.cc exceptions.cc decompress.cc PaletteDecoder.cc $(render_CXXSRCS) $(game_CXXSRCS)
objdecode_LIBS ::= -lSDL2 -lglbinding
objdecode_LIBS ::= -lSDL2 -lSDL2_ttf -lglbinding
progs ::= iffexplore treexplore mvedecode objdecode

View File

@@ -32,6 +32,28 @@ ObjDecoder::ObjDecoder(uint8_t const* base, size_t length)
}
}
ObjDecoder::Triangles ObjDecoder::getTriangles(unsigned lvl) const
{
Triangles ret;
for (auto idx : detailLevels_.at(lvl)) {
if (idx < triangles_.size())
ret.push_back(triangles_[idx]);
}
return ret;
}
ObjDecoder::Quads ObjDecoder::getQuads(unsigned lvl) const
{
Quads ret;
for (auto idx : detailLevels_.at(lvl)) {
if (idx >= triangles_.size())
ret.push_back(quads_[idx-triangles_.size()]);
}
return ret;
}
void ObjDecoder::parseOBJT_(IffFile::Form const& form)
{
}
@@ -73,7 +95,7 @@ void ObjDecoder::parsePOLY_(IffFile::Form const& form)
} else if (itForm.getSubtype() == "QUAD") {
parseQUAD_(itForm);
} else if (itForm.getSubtype() == "DETA") {
// NYI
parseDETA_(itForm);
} else if (itForm.getSubtype() == "TXMS") {
parseTXMS_(itForm);
} else if (itForm.getSubtype() == "GRUP") {
@@ -84,6 +106,8 @@ void ObjDecoder::parsePOLY_(IffFile::Form const& form)
// NYI
} else if (it->getType() == "XATR") {
// NYI
} else if (it->getType() == "SUPR") {
// NYI
} else
throw FormatException{"Unknown POLY child " + it->getType()};
}
@@ -117,7 +141,8 @@ void ObjDecoder::parseTRIS_(IffFile::Form const& form)
throw FormatException{"Unexpected FACE size"};
auto numTriangles = face->getSize()/8;
if (maps->getSize() != numTriangles*16)
throw FormatException{"Unexpected MAPS size"};
printf("WARNING: Unexpected MAPS size\n");
// throw FormatException{"Unexpected MAPS size"};
for (unsigned i = 0;i < numTriangles;++i) {
Triangle tri;
@@ -135,6 +160,8 @@ void ObjDecoder::parseTRIS_(IffFile::Form const& form)
// tri.vertIdx[2], tri.texCoords[2][0], tri.texCoords[2][1]);
triangles_.push_back(tri);
}
printf("TC: %lu\n", triangles_.size());
}
void ObjDecoder::parseQUAD_(IffFile::Form const& form)
@@ -162,7 +189,8 @@ void ObjDecoder::parseQUAD_(IffFile::Form const& form)
throw FormatException{"Unexpected FACE size"};
auto numQuads = face->getSize()/10;
if (maps->getSize() != numQuads*20)
throw FormatException{"Unexpected MAPS size"};
printf("WARNING: Unexpected MAPS size\n");
//throw FormatException{"Unexpected MAPS size"};
for (unsigned i = 0;i < numQuads;++i) {
Quad quad;
@@ -181,6 +209,33 @@ void ObjDecoder::parseQUAD_(IffFile::Form const& form)
// quad.vertIdx[3], quad.texCoords[3][0], quad.texCoords[3][1]);
quads_.push_back(quad);
}
printf("QC: %lu\n", quads_.size());
}
void ObjDecoder::parseDETA_(IffFile::Form const& form)
{
if (form.getChildCount() < 1)
throw FormatException{"Unexpected child count in DETA"};
unsigned lvl = 0;
for (auto it = form.childrenBegin();it != form.childrenEnd();++it) {
if (it->getType().substr(0, 3) != "LVL")
throw FormatException{"Unexpected child " + it->getType() + " in DETA"};
if (std::stoi(it->getType().substr(3)) != lvl)
throw FormatException{"Unexpected detail level"};
if (it->getSize() < 4)
throw FormatException{"DETA child too small"};
// uint32_t unkown = readU32LE(it->begin());
detailLevels_.emplace_back();
for (size_t pos = 4;pos < it->getSize()-1;pos += 2)
detailLevels_.back().push_back(readU16LE(it->begin()+pos));
printf("LVL %u: %lu entries\n", lvl, detailLevels_.back().size());
++lvl;
}
}
void ObjDecoder::parseTXMS_(IffFile::Form const& form)

View File

@@ -50,14 +50,16 @@ public:
return vertices_;
}
Triangles const& getTriangles() const {
return triangles_;
}
Quads const& getQuads() const {
return quads_;
Triangles getTriangles(unsigned lvl = 0) const;
Quads getQuads(unsigned lvl = 0) const;
unsigned getDetailLevels() const {
return detailLevels_.size();
}
using DetailLevel = std::vector<uint16_t>;
using DetailLevels = std::vector<DetailLevel>;
Textures const& getTextures() const {
return textures_;
}
@@ -74,6 +76,7 @@ private:
void parsePOLY_(IffFile::Form const& form);
void parseTRIS_(IffFile::Form const& form);
void parseQUAD_(IffFile::Form const& form);
void parseDETA_(IffFile::Form const& form);
void parseTXMS_(IffFile::Form const& form);
Vertices vertices_;
@@ -81,6 +84,7 @@ private:
Quads quads_;
Textures textures_;
TextureAnimations texAnims_;
DetailLevels detailLevels_;
};
#endif

View File

@@ -66,6 +66,10 @@ namespace game {
frameRGB_.resize(0);
}
bool GSMvePlay::handleEvent(SDL_Event& event)
{
return false;
}
void GSMvePlay::draw(unsigned delta_ms)
{

View File

@@ -16,7 +16,7 @@ namespace game {
~GSMvePlay() override;
void draw(unsigned delta_ms) override;
bool handleEvent(SDL_Event& event) override;
private:
MveDecoder::Movie& movie_;
std::unique_ptr<render::Overlay> overlay_;

View File

@@ -1,3 +1,5 @@
#include <glm/gtx/transform.hpp>
#include "ObjDecoder.hh"
#include "GSShowObject.hh"
@@ -7,7 +9,10 @@ namespace game {
GSShowObject::GSShowObject(render::Renderer& renderer, ObjDecoder& obj,
PaletteDecoder& palt)
: GameState(renderer), obj_(obj),
object_(nullptr), delta_(0)
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)
{
object_ = std::make_unique<render::Object>(renderer, obj, palt);
}
@@ -15,11 +20,108 @@ namespace game {
GSShowObject::~GSShowObject()
{
}
bool GSShowObject::handleEvent(SDL_Event& event)
{
switch (event.type) {
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_UP:
rotatingUD_ = Direction::Up;
break;
case SDLK_DOWN:
rotatingUD_ = Direction::Down;
break;
case SDLK_LEFT:
rotatingRL_ = Direction::Left;
break;
case SDLK_RIGHT:
rotatingRL_ = Direction::Right;
break;
case SDLK_w:
moveFB_ = Direction::Back;
break;
case SDLK_s:
moveFB_ = Direction::Front;
break;
case SDLK_a:
moveRL_ = Direction::Left;
break;
case SDLK_d:
moveRL_ = Direction::Right;
break;
}
break;
case SDL_KEYUP:
switch (event.key.keysym.sym) {
case SDLK_UP:
if (rotatingUD_ == Direction::Up)
rotatingUD_ = Direction::None;
break;
case SDLK_DOWN:
if (rotatingUD_ == Direction::Down)
rotatingUD_ = Direction::None;
break;
case SDLK_LEFT:
if (rotatingRL_ == Direction::Left)
rotatingRL_ = Direction::None;
break;
case SDLK_RIGHT:
if (rotatingRL_ == Direction::Right)
rotatingRL_ = Direction::None;
break;
case SDLK_w:
if (moveFB_ == Direction::Back)
moveFB_ = Direction::None;
break;
case SDLK_s:
if (moveFB_ == Direction::Front)
moveFB_ = Direction::None;
break;
case SDLK_a:
if (moveRL_ == Direction::Left)
moveRL_ = Direction::None;
break;
case SDLK_d:
if (moveRL_ == Direction::Right)
moveRL_ = Direction::None;
break;
}
break;
}
return false;
}
void GSShowObject::draw(unsigned delta_ms)
{
const float ROTATE_SCALE = 0.0005f, MOVE_SCALE = 50.0f;
delta_ += delta_ms;
object_->setRot(delta_*0.0005f);
if (rotatingUD_ == Direction::Up)
rotUD_ += delta_ms*ROTATE_SCALE;
else if (rotatingUD_ == Direction::Down)
rotUD_ -= delta_ms*ROTATE_SCALE;
if (rotatingRL_ == Direction::Left)
rotRL_ += delta_ms*ROTATE_SCALE;
else if (rotatingRL_ == Direction::Right)
rotRL_ -= delta_ms*ROTATE_SCALE;
if (moveFB_ == Direction::Back)
posZ_ += delta_ms*MOVE_SCALE;
else if (moveFB_ == Direction::Front)
posZ_ -= delta_ms*MOVE_SCALE;
if (moveRL_ == Direction::Left)
posX_ += delta_ms*MOVE_SCALE;
else if (moveRL_ == Direction::Right)
posX_ -= delta_ms*MOVE_SCALE;
object_->setTransform(glm::translate(glm::vec3(posX_, 0.0f, posZ_))*
glm::rotate(rotUD_, glm::vec3(1.0f, 0.0f, 0.0f))*
glm::rotate(rotRL_, glm::vec3(0.0f, 1.0f, 0.0f)));
object_->setAnimFrame((delta_/125)%8);
object_->draw();
}

View File

@@ -18,11 +18,24 @@ namespace game {
~GSShowObject() override;
void draw(unsigned delta_ms) override;
bool handleEvent(SDL_Event& event) override;
private:
ObjDecoder& obj_;
std::unique_ptr<render::Object> object_;
unsigned delta_;
enum class Direction {
Up,
Left,
Down,
Right,
None,
Front,
Back
};
Direction rotatingUD_, rotatingRL_, moveRL_, moveFB_;
float rotUD_, rotRL_, posX_, posZ_;
};
}

View File

@@ -1,6 +1,8 @@
#ifndef WC3RE_GAME_GAMESTATE_HH__
#define WC3RE_GAME_GAMESTATE_HH__
#include <SDL2/SDL.h>
namespace render {
class Renderer;
}
@@ -15,8 +17,16 @@ namespace game {
virtual ~GameState() {
}
/* Update and draw
* delta_ms is number of milliseconds since last call to draw
*/
virtual void draw(unsigned delta_ms) = 0;
/* Handle the event. Return true if the handler changes the current
* gamestate, false otherwise.
*/
virtual bool handleEvent(SDL_Event& event) = 0;
protected:
render::Renderer& renderer_;
};

View File

@@ -1,6 +1,8 @@
#ifndef WC3RE_RENDER_DRAWABLE_HH__
#define WC3RE_RENDER_DRAWABLE_HH__
#include <glm/glm.hpp>
namespace render {
class Renderer;
@@ -18,6 +20,25 @@ namespace render {
protected:
Renderer& renderer_;
};
class TransformDrawable : public Drawable {
public:
TransformDrawable(Renderer& renderer)
: Drawable(renderer), transformMatrix_() {
}
virtual void setTransform(glm::mat4 matrix) {
transformMatrix_ = matrix;
}
virtual glm::mat4 const& getTransform() const {
return transformMatrix_;
}
protected:
glm::mat4 transformMatrix_;
};
}
#endif

View File

@@ -39,40 +39,6 @@ namespace render {
}
};
const std::array<uint32_t, 256> vgaPalette = {
0x000000, 0x0000a8, 0x00a800, 0x00a8a8, 0xa80000, 0xa800a8, 0xa85400, 0xa8a8a8,
0x545454, 0x5454fc, 0x54fc54, 0x54fcfc, 0xfc5454, 0xfc54fc, 0xfcfc54, 0xfcfcfc,
0x000000, 0x141414, 0x202020, 0x2c2c2c, 0x383838, 0x444444, 0x505050, 0x606060,
0x707070, 0x808080, 0x909090, 0xa0a0a0, 0xb4b4b4, 0xc8c8c8, 0xe0e0e0, 0xfcfcfc,
0x0000fc, 0x4000fc, 0x7c00fc, 0xbc00fc, 0xfc00fc, 0xfc00bc, 0xfc007c, 0xfc0040,
0xfc0000, 0xfc4000, 0xfc7c00, 0xfcbc00, 0xfcfc00, 0xbcfc00, 0x7cfc00, 0x40fc00,
0x00fc00, 0x00fc40, 0x00fc7c, 0x00fcbc, 0x00fcfc, 0x00bcfc, 0x007cfc, 0x0040fc,
0x7c7cfc, 0x9c7cfc, 0xbc7cfc, 0xdc7cfc, 0xfc7cfc, 0xfc7cdc, 0xfc7cbc, 0xfc7c9c,
0xfc7c7c, 0xfc9c7c, 0xfcbc7c, 0xfcdc7c, 0xfcfc7c, 0xdcfc7c, 0xbcfc7c, 0x9cfc7c,
0x7cfc7c, 0x7cfc9c, 0x7cfcbc, 0x7cfcdc, 0x7cfcfc, 0x7cdcfc, 0x7cbcfc, 0x7c9cfc,
0xb4b4fc, 0xc4b4fc, 0xd8b4fc, 0xe8b4fc, 0xfcb4fc, 0xfcb4e8, 0xfcb4d8, 0xfcb4c4,
0xfcb4b4, 0xfcc4b4, 0xfcd8b4, 0xfce8b4, 0xfcfcb4, 0xe8fcb4, 0xd8fcb4, 0xc4fcb4,
0xb4fcb4, 0xb4fcc4, 0xb4fcd8, 0xb4fce8, 0xb4fcfc, 0xb4e8fc, 0xb4d8fc, 0xb4c4fc,
0x000070, 0x1c0070, 0x380070, 0x540070, 0x700070, 0x700054, 0x700038, 0x70001c,
0x700000, 0x701c00, 0x703800, 0x705400, 0x707000, 0x547000, 0x387000, 0x1c7000,
0x007000, 0x00701c, 0x007038, 0x007054, 0x007070, 0x005470, 0x003870, 0x001c70,
0x383870, 0x443870, 0x543870, 0x603870, 0x703870, 0x703860, 0x703854, 0x703844,
0x703838, 0x704438, 0x705438, 0x706038, 0x707038, 0x607038, 0x547038, 0x447038,
0x387038, 0x387044, 0x387054, 0x387060, 0x387070, 0x386070, 0x385470, 0x384470,
0x505070, 0x585070, 0x605070, 0x685070, 0x705070, 0x705068, 0x705060, 0x705058,
0x705050, 0x705850, 0x706050, 0x706850, 0x707050, 0x687050, 0x607050, 0x587050,
0x507050, 0x507058, 0x507060, 0x507068, 0x507070, 0x506870, 0x506070, 0x505870,
0x000040, 0x100040, 0x200040, 0x300040, 0x400040, 0x400030, 0x400020, 0x400010,
0x400000, 0x401000, 0x402000, 0x403000, 0x404000, 0x304000, 0x204000, 0x104000,
0x004000, 0x004010, 0x004020, 0x004030, 0x004040, 0x003040, 0x002040, 0x001040,
0x202040, 0x282040, 0x302040, 0x382040, 0x402040, 0x402038, 0x402030, 0x402028,
0x402020, 0x402820, 0x403020, 0x403820, 0x404020, 0x384020, 0x304020, 0x284020,
0x204020, 0x204028, 0x204030, 0x204038, 0x204040, 0x203840, 0x203040, 0x202840,
0x2c2c40, 0x302c40, 0x342c40, 0x3c2c40, 0x402c40, 0x402c3c, 0x402c34, 0x402c30,
0x402c2c, 0x40302c, 0x40342c, 0x403c2c, 0x40402c, 0x3c402c, 0x34402c, 0x30402c,
0x2c402c, 0x2c4030, 0x2c4034, 0x2c403c, 0x2c4040, 0x2c3c40, 0x2c3440, 0x2c3040,
0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000};
struct TexAtlasInfo {
unsigned x, y;
unsigned alignWidth, alignHeight;
@@ -89,27 +55,42 @@ namespace render {
std::tie(maxTex, maxLayers) = getGLTextureMaximums();
printf("Maximum texture size: %d, maximum array texture layers: %d\n", maxTex, maxLayers);
// If the atlas gets too large we may have problems with texture coordinate precision
if (maxTex > 8192)
maxTex = 8192;
unsigned minSize = std::numeric_limits<unsigned>::max();
unsigned accumWidth = 0, maxHeight = 0;
for (auto& tex : texs) {
minSize = std::min<unsigned>(minSize, std::min<unsigned>(tex.width, tex.height));
accumWidth += tex.width;
maxHeight = std::max<unsigned>(maxHeight, tex.height);
}
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)));
printf("Squarified target width %u\n", accumWidth2);
std::vector<TexAtlasInfo> ret;
unsigned xpos = 0, ypos = 0, lineMaxHeight = 0;
unsigned xpos = 0, ypos = 0, lineMaxHeight = 0, maxWidth = 0;
for (auto& tex : texs) {
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 > static_cast<unsigned>(maxTex)) {
if (xpos + alignWidth > accumWidth2) {
ypos += lineMaxHeight;
maxWidth = std::max(maxWidth, xpos);
lineMaxHeight = 0;
xpos = 0;
}
@@ -122,12 +103,12 @@ namespace render {
lineMaxHeight = std::max<unsigned>(lineMaxHeight, alignHeight);
xpos += alignWidth;
}
unsigned atlasWidth = xpos, atlasHeight = ypos+lineMaxHeight;
unsigned atlasWidth = std::max(xpos, maxWidth), atlasHeight = ypos+lineMaxHeight;
printf("Texture atlas size: %ux%u\n", atlasWidth, atlasHeight);
TextureResource tex = create2DTexture(atlasWidth, atlasHeight, false, minLg+1);
TextureResource tex = create2DTexture(atlasWidth, atlasHeight, true, minLg+1);
std::vector<uint8_t> pixels(atlasWidth*atlasHeight*3);
std::vector<uint8_t> pixels(atlasWidth*atlasHeight*4);
// Copy textures into atlas
for (auto& info : ret) {
info.xofs = (info.x+0.5f)/atlasWidth;
@@ -153,13 +134,21 @@ namespace render {
col = info.tex.pixels[info.tex.height*info.tex.width - 1];
}
}
pixels[(y+info.y)*atlasWidth*3+(info.x+x)*3] = palt[col*3]; //vgaPalette[col]>>16;
pixels[(y+info.y)*atlasWidth*3+(info.x+x)*3+1] = palt[col*3+1]; //vgaPalette[col]>>8;
pixels[(y+info.y)*atlasWidth*3+(info.x+x)*3+2] = palt[col*3+2]; //vgaPalette[col];
if (col == 0xff) {
pixels[(y+info.y)*atlasWidth*4+(info.x+x)*4] = 0u;
pixels[(y+info.y)*atlasWidth*4+(info.x+x)*4+1] = 0u;
pixels[(y+info.y)*atlasWidth*4+(info.x+x)*4+2] = 0u;
pixels[(y+info.y)*atlasWidth*4+(info.x+x)*4+3] = 0u;
} else {
pixels[(y+info.y)*atlasWidth*4+(info.x+x)*4] = palt[col*3+2]; //vgaPalette[col]>>16;
pixels[(y+info.y)*atlasWidth*4+(info.x+x)*4+1] = palt[col*3+1]; //vgaPalette[col]>>8;
pixels[(y+info.y)*atlasWidth*4+(info.x+x)*4+2] = palt[col*3]; //vgaPalette[col];
pixels[(y+info.y)*atlasWidth*4+(info.x+x)*4+3] = 255u;
}
}
}
}
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, atlasWidth, atlasHeight, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, atlasWidth, atlasHeight, GL_BGRA, GL_UNSIGNED_BYTE, pixels.data());
glGenerateMipmap(GL_TEXTURE_2D);
return std::make_tuple(std::move(ret), std::move(tex));
@@ -177,7 +166,7 @@ namespace render {
if (width%4 != 0)
width += 4 - (width%4);
unsigned height = texAnim.height;
TextureResource tex = create2DArrayTexture(width, height, texAnim.frames, false);
TextureResource tex = create2DArrayTexture(width, height, texAnim.frames, true);
AnimTexInfo animInfo;
animInfo.xofs = 0.5f/width;
@@ -185,21 +174,29 @@ namespace render {
animInfo.xscale = (texAnim.width-1.0f)/(width*texAnim.width);
animInfo.yscale = (texAnim.height-1.0f)/(height*texAnim.height);
std::vector<uint8_t> pixels(texAnim.frames*width*height*3);
std::vector<uint8_t> pixels(texAnim.frames*width*height*4);
for (unsigned f = 0;f < texAnim.frames;++f) {
for (unsigned y = 0;y < texAnim.height;++y) {
for (unsigned x = 0;x < texAnim.width;++x) {
unsigned col = texAnim.pixels[f][y*texAnim.width+x];
pixels[f*width*height*3+y*width*3+x*3] = palt[col*3];
pixels[f*width*height*3+y*width*3+x*3+1] = palt[col*3+1];
pixels[f*width*height*3+y*width*3+x*3+2] = palt[col*3+2];
if (col == 0xff) {
pixels[f*width*height*4+y*width*4+x*4] = 0u;
pixels[f*width*height*4+y*width*4+x*4+1] = 0u;
pixels[f*width*height*4+y*width*4+x*4+2] = 0u;
pixels[f*width*height*4+y*width*4+x*4+3] = 0u;
} else {
pixels[f*width*height*4+y*width*4+x*4] = palt[col*3+2];
pixels[f*width*height*4+y*width*4+x*4+1] = palt[col*3+1];
pixels[f*width*height*4+y*width*4+x*4+2] = palt[col*3];
pixels[f*width*height*4+y*width*4+x*4+3] = 255u;
}
}
}
}
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, texAnim.frames,
GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
GL_BGRA, GL_UNSIGNED_BYTE, pixels.data());
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
return std::make_tuple(animInfo, std::move(tex));
@@ -209,8 +206,8 @@ namespace render {
genVertexAttribs(ObjDecoder& obj, std::vector<TexAtlasInfo>& atlasInfo,
AnimTexInfo *animTex = nullptr)
{
auto& tris = obj.getTriangles();
auto& quads = obj.getQuads();
auto tris = obj.getTriangles();
auto quads = obj.getQuads();
// Deduplicate vertex attributes, track indices
std::map<VertexAttribs, size_t> vertexAttribsMap;
@@ -302,7 +299,7 @@ namespace render {
}
Object::Object(Renderer& renderer, ObjDecoder& obj, PaletteDecoder& palt)
: Drawable(renderer),
: TransformDrawable(renderer),
vbo_(), rot_(0.0f), animFrame_(0)
{
// Acquire shader
@@ -362,9 +359,9 @@ namespace render {
2*numIndices_,
indices.data());
mvp_ = glm::perspectiveFov(75.0f, static_cast<float>(renderer.getWidth()),
vp_ = glm::perspectiveFov(75.0f, static_cast<float>(renderer.getWidth()),
static_cast<float>(renderer.getHeight()),
1000.f, 800000.0f) *
7500.f, 800000.0f) *
glm::lookAt(glm::vec3(0.0f, 0.0f, 200000),
glm::vec3(0.0f, 0.0f, 0),
glm::vec3(0, 1, 0));
@@ -386,22 +383,24 @@ namespace render {
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
useProgram(program_);
glUniformMatrix4fv(0, 1, GL_FALSE,
glm::value_ptr(mvp_*glm::rotate(rot_, glm::vec3(1.0f, 0.0f, 0.0f))));
glUniform1i(1, 0);
glUniform1i(2, 1);
glm::value_ptr(vp_));
glUniformMatrix4fv(1, 1, GL_FALSE,
glm::value_ptr(transformMatrix_));
glUniform1i(2, 0);
glUniform1i(3, 1);
glBindTexture(GL_TEXTURE_2D, tex_);
if (texAnim_) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D_ARRAY, texAnim_);
glActiveTexture(GL_TEXTURE0);
glUniform1ui(3, animFrame_);
glUniform1ui(4, animFrame_);
}
glBindVertexArray(vertexArray_);
glDrawRangeElements(GL_TRIANGLES, 0, maxIndex_,
numIndices_, GL_UNSIGNED_SHORT, reinterpret_cast<void*>(indexOfs_));
numIndices_, GL_UNSIGNED_SHORT, vbo_.getOfs(indexOfs_));
}
}

View File

@@ -12,14 +12,10 @@ class ObjDecoder;
class PaletteDecoder;
namespace render {
class Object : public Drawable {
class Object : public TransformDrawable {
public:
Object(Renderer& renderer, ObjDecoder& obj, PaletteDecoder& palt);
void setRot(float rot) {
rot_ = rot;
}
void setAnimFrame(unsigned frame) {
animFrame_ = frame;
}
@@ -31,7 +27,7 @@ namespace render {
gl::GLuint program_;
VBOManager::VBOAlloc vbo_;
TextureResource tex_, texAnim_;
glm::mat4 mvp_;
glm::mat4 vp_;
uintptr_t indexOfs_;
size_t numIndices_, maxIndex_;
float rot_;

View File

@@ -17,11 +17,11 @@ namespace render {
struct VertexAttribs {
int16_t vertex[2];
uint16_t texCoords[2];
} __attribute__((__packed__));
};
}
Overlay::Overlay(Renderer& renderer, int width, int height, int left, int top, int intWidth, int intHeight)
: Drawable(renderer), texture_(create2DTexture(intWidth, intHeight, false, 1)),
: Drawable(renderer), texture_(create2DTexture(intWidth, intHeight, true, 1)),
vbo_(VBOManager::getInstance().alloc(sizeof(VertexAttribs)*6)),
width_(width), height_(height), top_(top), left_(left), intWidth_(intWidth), intHeight_(intHeight)
{
@@ -71,22 +71,32 @@ namespace render {
glDrawArrays(GL_TRIANGLES, 0, 6);
}
void Overlay::clear()
{
if (SDL_GL_ExtensionSupported("GL_ARB_clear_texture"))
glClearTexImage(texture_, 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);
else {
std::vector<uint8_t> zeros(intWidth_*intHeight_*4, 0u);
setContentBGRA8(zeros.data());
}
}
void Overlay::setContent(SDL_Surface *content)
{
if (!content ||
(content->h != intHeight_) ||
(content->w != intWidth_))
(content->h > intHeight_) ||
(content->w > intWidth_))
throw Exception{"null or mismatched surface"};
glBindTexture(GL_TEXTURE_2D, texture_);
if (content->format->format != SDL_PIXELFORMAT_RGB24) {
SDLSurfaceUPtr tmpSurf(SDL_ConvertSurfaceFormat(content, SDL_PIXELFORMAT_RGB24, 0));
if (content->format->format != SDL_PIXELFORMAT_ARGB8888) {
SDLSurfaceUPtr tmpSurf(SDL_ConvertSurfaceFormat(content, SDL_PIXELFORMAT_ARGB8888, 0));
if (!tmpSurf)
throw SDLException{};
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tmpSurf->w, tmpSurf->h, GL_RGB, GL_UNSIGNED_BYTE, tmpSurf->pixels);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tmpSurf->w, tmpSurf->h, GL_BGRA, GL_UNSIGNED_BYTE, tmpSurf->pixels);
} else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, content->w, content->h, GL_RGB, GL_UNSIGNED_BYTE, content->pixels);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, content->w, content->h, GL_BGRA, GL_UNSIGNED_BYTE, content->pixels);
}
void Overlay::setContentRGB8(void *data)
@@ -94,4 +104,10 @@ namespace render {
glBindTexture(GL_TEXTURE_2D, texture_);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, intWidth_, intHeight_, GL_RGB, GL_UNSIGNED_BYTE, data);
}
void Overlay::setContentBGRA8(void *data)
{
glBindTexture(GL_TEXTURE_2D, texture_);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, intWidth_, intHeight_, GL_BGRA, GL_UNSIGNED_BYTE, data);
}
}

View File

@@ -18,8 +18,11 @@ namespace render {
void draw() override;
void clear();
void setContent(SDL_Surface *content);
void setContentRGB8(void *data);
void setContentBGRA8(void *data);
private:
TextureResource texture_;
VertexArrayResource vertexArray_;

View File

@@ -1,11 +1,13 @@
#include <glbinding/gl/gl.h>
#include <glbinding/Binding.h>
#include <glbinding/callbacks.h>
#include <glbinding/Meta.h>
#include "Renderer.hh"
#include "GlResource.hh"
#include "game/GameState.hh"
#include "exceptions.hh"
#include "Overlay.hh"
using namespace gl;
@@ -57,10 +59,12 @@ namespace render {
Renderer::Renderer()
: sdlInit_(), window_(), context_()
: sdlInit_(), ttfInit_(), window_(), context_()
{
glbinding::Binding::initialize();
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
@@ -82,46 +86,95 @@ namespace render {
#ifndef NDEBUG
{
int depth, stencil, aa, major, minor;
SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depth);
SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil);
SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &aa);
int major, minor;
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
printf("Depth: %d, Stencil: %d, AA: %d, GL %d.%d\n",
depth, stencil, aa, major, minor);
printf("GL %d.%d\n",
major, minor);
}
#endif
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glViewport(0, 0, width_, height_);
fpsFont_.reset(TTF_OpenFont("DejaVuSans.ttf", 10));
if (!fpsFont_)
throw TTFException{};
SDL_Color white;
white.r = 255;
white.g = 255;
white.b = 255;
white.a = 255;
SDLSurfaceUPtr fpsSurf(TTF_RenderUTF8_Blended(fpsFont_.get(), "0 FPS", white));
if (!fpsSurf)
throw TTFException{};
fpsOverlay_ = std::make_unique<Overlay>(*this, fpsSurf->w*2, fpsSurf->h, 0, 0, fpsSurf->w*2, fpsSurf->h);
fpsOverlay_->clear();
fpsOverlay_->setContent(fpsSurf.get());
}
Renderer::~Renderer()
{
}
void Renderer::run()
{
bool close = false;
auto last = SDL_GetTicks();
unsigned fpsTime = 0, fpsCount = 0, lastFps = 0;
while (!close && gamestates_.size()) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_q)
if (event.key.keysym.sym == SDLK_q) {
close = true;
continue;
}
break;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_CLOSE)
if (event.window.event == SDL_WINDOWEVENT_CLOSE) {
close = true;
continue;
}
break;
}
if (gamestates_.back()->handleEvent(event))
continue;
break;
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auto now = SDL_GetTicks();
auto delta = now-last;
gamestates_.back()->draw(delta);
gamestates_.back()->draw(now-last);
if (fpsTime+delta > 1000) {
if (fpsCount+1 != lastFps) {
std::string fpsText{std::to_string(fpsCount+1) + " FPS"};
SDLSurfaceUPtr fpsSurf(TTF_RenderUTF8_Blended(fpsFont_.get(), fpsText.c_str(),
SDL_Color({255, 255, 255, 255})));
if (!fpsSurf)
throw TTFException{};
fpsOverlay_->clear();
fpsOverlay_->setContent(fpsSurf.get());
lastFps = fpsCount+1;
}
fpsCount = 0;
fpsTime = 0;
} else {
++fpsCount;
fpsTime += delta;
}
fpsOverlay_->draw();
SDL_GL_SwapWindow(window_.get());
last = now;

View File

@@ -1,6 +1,8 @@
#ifndef WC3RE_RENDER_RENDERER_HH__
#define WC3RE_RENDER_RENDERER_HH__
#include <memory>
#include "sdlutil.hh"
namespace game {
@@ -8,10 +10,13 @@ namespace game {
}
namespace render {
class Overlay;
class Renderer {
public:
Renderer();
~Renderer();
void run();
int getWidth() const;
@@ -21,10 +26,13 @@ namespace render {
std::unique_ptr<game::GameState> popGS();
private:
SDLInit sdlInit_;
TTFInit ttfInit_;
SDLWindowUPtr window_;
SDLGLContext context_;
std::vector<std::unique_ptr<game::GameState> > gamestates_;
int width_, height_;
TTFFontUPtr fpsFont_;
std::unique_ptr<Overlay> fpsOverlay_;
};
}

View File

@@ -27,7 +27,7 @@ namespace render {
class VBO;
static const size_t default_size = 1048576;
static const size_t alignment = 8;
static const size_t alignment = 4;
static const gl::GLenum default_type = gl::GL_STATIC_DRAW;
class AllocFailed {};

View File

@@ -5,6 +5,7 @@
#include <cstdint>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include "exceptions.hh"
@@ -19,6 +20,17 @@ namespace render {
return "SDLException: " + msg_;
}
};
class TTFException : public Exception {
public:
TTFException() : Exception(TTF_GetError()) {
}
std::string toString() const override {
return "TTFException: " + msg_;
}
};
// Some helpers to C++11-ify SDL
struct SDLSurfaceDeleter {
@@ -36,6 +48,14 @@ namespace render {
};
using SDLWindowUPtr = std::unique_ptr<SDL_Window, SDLWindowDeleter>;
struct TTFFontDeleter {
void operator()(TTF_Font* font) const {
TTF_CloseFont(font);
}
};
using TTFFontUPtr = std::unique_ptr<TTF_Font, TTFFontDeleter>;
class SDLSurfaceScopedLock {
@@ -94,6 +114,23 @@ namespace render {
}
};
// RAII wrapper for TTF_Init
class TTFInit {
public:
TTFInit() {
if (TTF_Init() < 0)
throw TTFException{};
}
TTFInit(TTFInit const& copy) = delete;
TTFInit& operator=(TTFInit const& copy) = delete;
~TTFInit() {
TTF_Quit();
}
};
// RAII wrapper for SDL_GLContext
class SDLGLContext {
public:

View File

@@ -1,21 +1,30 @@
#version 330 core
#extension GL_ARB_explicit_uniform_location : enable
#extension GL_ARB_conservative_depth : enable
layout(location = 1) uniform sampler2D texBase;
layout(location = 2) uniform sampler2DArray texAnim;
layout(location = 3) uniform uint animFrame;
layout(location = 2) uniform sampler2D texBase;
layout(location = 3) uniform sampler2DArray texAnim;
layout(location = 4) uniform uint animFrame;
layout(location = 5) uniform vec3 IDcolor;
in vec2 fragTC;
flat in uint fragUseAnimTex;
out vec4 color;
layout(location = 0) out vec4 color;
layout(location = 1) out vec4 IDcolor_out;
layout(depth_unchanged) out float gl_FragDepth;
void main(void) {
vec2 texDx = dFdx(fragTC);
vec2 texDy = dFdy(fragTC);
if (fragUseAnimTex > 0u)
color = textureGrad(texAnim, vec3(fragTC, animFrame), texDx, texDy);
//color = vec4(1.0, 1.0, 0.0, 1.0);
else
color = textureGrad(texBase, fragTC, texDx, texDy);
if (color.w < 0.5)
discard;
IDcolor_out = vec4(IDcolor, 1.0);
}

View File

@@ -2,7 +2,8 @@
#extension GL_ARB_shading_language_420pack : enable
#extension GL_ARB_explicit_uniform_location : enable
layout(location = 0) uniform mat4 mvp_matrix;
layout(location = 0) uniform mat4 vp_matrix;
layout(location = 1) uniform mat4 m_matrix;
layout(location = 0) in vec3 vertex;
layout(location = 1) in vec2 vertexTC;
@@ -12,8 +13,8 @@ out vec2 fragTC;
flat out uint fragUseAnimTex;
void main(void) {
gl_Position = mvp_matrix * vec4(vertex, 1.0);
gl_Position = vp_matrix * m_matrix * vec4(vertex, 1.0);
fragTC = vertexTC;
fragUseAnimTex = useAnimTex;
fragTC = vertexTC;
fragUseAnimTex = useAnimTex;
}

View File

@@ -5,8 +5,9 @@ layout(location = 1) uniform sampler2D texBase;
in vec2 fragTC;
out vec4 color;
layout(location = 0) out vec4 color;
void main(void) {
color = texture(texBase, fragTC);
vec4 texCol = texture(texBase, fragTC);
color = texCol*texCol.w;
}