PNG loading and major refactoring.

PNG loading is not working properly yet.
This commit is contained in:
King_DuckZ 2014-02-21 21:51:56 +01:00
parent d0893cba3a
commit 28bd73a1f7
17 changed files with 254 additions and 43 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View file

@ -35,4 +35,11 @@ namespace cloonel {
void Character::Destroy() noexcept {
m_texture->Destroy();
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
void Character::Draw() const {
const int2 pos(m_pos + 0.5f);
m_texture->Render(pos);
}
} //namespace cloonel

View file

@ -2,6 +2,7 @@
#define id0CEACFB045ED4C9F8688265AA41E30B0
#include "placeable.hpp"
#include "drawable.hpp"
#include "vector.hpp"
#include <string>
#include <memory>
@ -10,14 +11,15 @@ namespace cloonel {
class SDLMain;
class Texture;
class Character : public Placeable {
class Character : public Placeable, public Drawable {
public:
Character ( const std::string& parPath, SDLMain* parMain );
Character ( const std::string&& parPath, SDLMain* parMain );
~Character ( void ) noexcept;
virtual ~Character ( void ) noexcept;
void Prepare ( void );
void Destroy ( void ) noexcept;
virtual void Draw ( void ) const;
private:
const std::unique_ptr<Texture> m_texture;

14
src/drawable.hpp Normal file
View file

@ -0,0 +1,14 @@
#ifndef idC5A880D06A03407DB4E9FC21593A47FB
#define idC5A880D06A03407DB4E9FC21593A47FB
namespace cloonel {
class Drawable {
public:
Drawable ( void ) = default;
virtual ~Drawable ( void ) noexcept = default;
virtual void Draw ( void ) const = 0;
};
} //namespace cloonel
#endif

View file

@ -19,6 +19,8 @@ namespace cloonel {
virtual void Prepare ( void ) = 0;
virtual void Destroy ( void ) noexcept = 0;
SDLMain* SDLObject ( void ) { return m_sdlmain; }
private:
virtual void OnRender ( void ) = 0;
virtual void OnUpdate ( float parDelta ) = 0;

View file

@ -1,5 +1,6 @@
#include "gameplayscene.hpp"
#include "mover.hpp"
#include "drawable.hpp"
namespace cloonel {
///--------------------------------------------------------------------------
@ -20,5 +21,8 @@ namespace cloonel {
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void GameplayScene::OnRender() {
for (auto itDrawable : m_drawables) {
itDrawable->Draw();
}
}
} //namespace cloonel

View file

@ -2,23 +2,27 @@
#define id1DF84BC48C0547D69F79499E3A25BFC5
#include <vector>
#include <cassert>
#include "gamebase.hpp"
namespace cloonel {
class Mover;
class Drawable;
class GameplayScene : public GameBase {
public:
explicit GameplayScene ( SDLMain* parSdlMain );
virtual ~GameplayScene ( void ) noexcept = default;
void AddMover ( Mover* parMover ) { m_movers.push_back(parMover); }
void AddMover ( Mover* parMover ) { assert(parMover); m_movers.push_back(parMover); }
void AddDrawable ( const Drawable* parDrawable ) { assert(parDrawable); m_drawables.push_back(parDrawable); }
private:
virtual void OnRender ( void );
virtual void OnUpdate ( float parDelta );
std::vector<Mover*> m_movers;
std::vector<const Drawable*> m_drawables;
};
} //namespace cloonel

View file

@ -1,10 +1,17 @@
#include "gameplaysceneclassic.hpp"
#include "character.hpp"
#include "moversine.hpp"
#include <algorithm>
namespace cloonel {
struct GameplaySceneClassic::LocalData {
};
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
GameplaySceneClassic::GameplaySceneClassic (SDLMain* parSdlMain) :
GameplayScene(parSdlMain)
GameplayScene(parSdlMain),
m_local(new LocalData)
{
}
@ -17,10 +24,23 @@ namespace cloonel {
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void GameplaySceneClassic::Prepare() {
std::unique_ptr<MoverSine> moverSine(new MoverSine());
std::unique_ptr<Character> player(new Character("resources/graphics/player.png", SDLObject()));
player->Prepare();
player->SwapMover(moverSine.get());
std::swap(moverSine, m_moverSine);
std::swap(player, m_player);
AddMover(m_moverSine.get());
AddDrawable(m_player.get());
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void GameplaySceneClassic::Destroy() noexcept {
m_moverSine = std::move(std::unique_ptr<MoverSine>(nullptr));
m_player = std::move(std::unique_ptr<Character>(nullptr));
}
} //namespace cloonel

View file

@ -2,9 +2,12 @@
#define idF6FF1F57C36842DC9B20E2F55C507C2E
#include "gameplayscene.hpp"
#include <memory>
namespace cloonel {
class SDLMain;
class Character;
class MoverSine;
class GameplaySceneClassic : public GameplayScene {
public:
@ -15,6 +18,11 @@ namespace cloonel {
virtual void Destroy ( void ) noexcept;
private:
struct LocalData;
const std::unique_ptr <LocalData> m_local;
std::unique_ptr<Character> m_player;
std::unique_ptr<MoverSine> m_moverSine;
};
} //namespace cloonel

View file

@ -10,27 +10,25 @@ namespace {
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
void RunMainLoop (cloonel::GameplaySceneClassic& parGame) {
parGame.Prepare();
do {
parGame.Exec();
} while (not parGame.WantsToQuit());
parGame.Destroy();
}
} //unnamed namespace
///----------------------------------------------------------------------------
///following http://twinklebeardev.blogspot.co.uk/2012/07/lesson-1-hello-world.html
///----------------------------------------------------------------------------
int main (int, char* []) {
int main (int, char* parArgv[]) {
std::cout << GameName << " v" << GameVersionMajor << "." << GameVersionMinor << std::endl;
int retVal = 0;
cloonel::SDLMain sdlmain(GameName, DEF_WIN_WIDTH, DEF_WIN_HEIGHT);
try {
#if defined(NDEBUG)
cloonel::PhysicsFSWrapper physfs(parArgc[0]);
#else
cloonel::PhysicsFSWrapper physfs(GAME_BASE_PATH);
#endif
physfs.Append("resources", "resources");
cloonel::PhysicsFSWrapper physfs(parArgv[0]);
physfs.Append(GAME_BASE_PATH "/resources/", "resources");
sdlmain.Init();

View file

@ -1,12 +1,38 @@
#include "mover.hpp"
#include "placeable.hpp"
#include <cassert>
#include <algorithm>
namespace cloonel {
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void Mover::ApplyOffsetToPlaceable (std::size_t parIndex, const float2& parOffset) {
assert(m_placeables[parIndex]);
m_placeables[parIndex]->AddOffset(parOffset);
void Mover::ApplyOffsetToPlaceables (const float2& parOffset) {
for (Placeable* currPlaceable : m_placeables) {
if (currPlaceable) {
currPlaceable->AddOffset(parOffset);
}
}
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
int Mover::RegisterPlaceable (Placeable* parPlaceable) {
assert(parPlaceable);
m_placeables.push_back(parPlaceable);
const std::size_t retVal = m_placeables.size();
return static_cast<int>(retVal);
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void Mover::UnregisterPlaceable (int parID) {
assert(static_cast<std::size_t>(parID) <= m_placeables.size());
assert(m_placeables[parID - 1]);
m_placeables[parID - 1] = nullptr;
auto lastNull = std::find_if(m_placeables.rbegin(), m_placeables.rend(), [](const Placeable* parPlaceable) { return nullptr != parPlaceable; });
if (m_placeables.rend() != lastNull) {
m_placeables.resize(m_placeables.size() - (lastNull - m_placeables.rbegin()) + 1);
}
}
} //namespace cloonel

View file

@ -13,12 +13,13 @@ namespace cloonel {
virtual ~Mover ( void ) noexcept = default;
virtual void ApplyMotion ( float parDelta ) = 0;
void AddPlaceable ( Placeable* parPlaceable ) { m_placeables.push_back(parPlaceable); }
int RegisterPlaceable ( Placeable* parPlaceable );
void UnregisterPlaceable ( int parID );
protected:
virtual void Update ( float parDelta ) = 0;
std::size_t PlaceableCount ( void ) const { return m_placeables.size(); }
void ApplyOffsetToPlaceable ( std::size_t parIndex, const float2& parOffset );
void ApplyOffsetToPlaceables ( const float2& parOffset );
private:
std::vector<Placeable*> m_placeables;

View file

@ -6,9 +6,6 @@ namespace cloonel {
void MoverOneShot::ApplyMotion (float parDelta) {
Update(parDelta);
const float2 offs(GetOffset());
const std::size_t placeableCount = PlaceableCount();
for (std::size_t z = 0; z < placeableCount; ++z) {
ApplyOffsetToPlaceable(z, offs);
}
ApplyOffsetToPlaceables(offs);
}
} //namespace cloonel

View file

@ -1,10 +1,29 @@
#include "placeable.hpp"
#include "mover.hpp"
#include <cassert>
namespace cloonel {
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
Placeable::Placeable (float parX, float parY) :
m_pos(parX, parY)
m_pos(parX, parY),
m_mover(nullptr),
m_idForMover(0)
{
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
void Placeable::SwapMover (Mover* parMover) {
if (m_mover) {
assert(0 != m_idForMover);
m_mover->UnregisterPlaceable(m_idForMover);
m_idForMover = 0;
m_mover = nullptr;
}
if (parMover) {
m_idForMover = parMover->RegisterPlaceable(this);
m_mover = parMover;
}
}
} //namespace cloonel

View file

@ -4,16 +4,24 @@
#include "vector.hpp"
namespace cloonel {
class Mover;
class Placeable {
public:
const float2& GetPos ( void ) const noexcept { return m_pos; }
void AddOffset ( const float2& parOffset ) noexcept { m_pos += parOffset; }
void SwapMover ( Mover* parMover );
protected:
Placeable ( float parX, float parY );
~Placeable ( void ) noexcept = default;
float2 m_pos;
private:
Mover* m_mover;
int m_idForMover;
};
} //namespace cloonel

View file

@ -8,12 +8,31 @@
#include <ciso646>
#include <png.h>
#define lengthof(a) (static_cast<int32_t>(sizeof(a)) / static_cast<int32_t>(sizeof(a[0])))
namespace cloonel {
namespace {
enum GraphicFormat {
GraphicFormat_Unknown,
GraphicFormat_Png
};
enum ColorChannelMask {
#if SDL_BYTE_ORDER == SDL_BIGENDIAN
ColorChannelMask_Red = 0xff000000,
ColorChannelMask_Green = 0xff0000,
ColorChannelMask_Blue = 0xff00,
ColorChannelMask_Alpha = 0xff
#elif SDL_BYTE_ORDER == SDL_LITTLEENDIAN
ColorChannelMask_Red = 0xff,
ColorChannelMask_Green = 0xff00,
ColorChannelMask_Blue = 0xff0000,
ColorChannelMask_Alpha = 0xff000000
#else
# error "Unknonwn endianness"
#endif
};
struct GraphicFormatItem {
const char* extension;
size_t length;
@ -26,8 +45,34 @@ namespace cloonel {
GraphicFormat GuessGraphicFormatFromName (const std::string& parPath) __attribute__((pure));
///--------------------------------------------------------------------
///--------------------------------------------------------------------
///----------------------------------------------------------------------
///----------------------------------------------------------------------
SDL_Surface* SurfaceFromPngRGBA (ushort2 parSize, int parBpp, const png_structp& parPngPtr, const png_infop& parInfoPtr) {
const png_size_t stride = png_get_rowbytes(parPngPtr, parInfoPtr);
assert(stride > 0);
std::unique_ptr<uint8_t[]> image(new uint8_t[stride * parSize.y()]);
uint8_t* const imagePtr = image.get();
for (uint16_t y = 0; y < parSize.y(); ++y) {
png_read_row(parPngPtr, imagePtr + stride * y, nullptr);
}
SDL_Surface* const retSurf = SDL_CreateRGBSurfaceFrom(
imagePtr,
parSize.x(),
parSize.y(),
parBpp,
static_cast<int>(stride),
ColorChannelMask_Red,
ColorChannelMask_Green,
ColorChannelMask_Blue,
ColorChannelMask_Alpha
);
return retSurf;
}
///----------------------------------------------------------------------
///----------------------------------------------------------------------
GraphicFormat GuessGraphicFormatFromName (const std::string& parPath) {
const size_t dotPos = parPath.find_last_of('.');
if (parPath.npos == dotPos) {
@ -44,27 +89,82 @@ namespace cloonel {
return GraphicFormat_Unknown;
}
///--------------------------------------------------------------------
///--------------------------------------------------------------------
///----------------------------------------------------------------------
///----------------------------------------------------------------------
void ReadDataFromInputStream (png_structp parPngPtr, png_bytep parOutBytes, png_size_t parByteCountToRead) {
if (not png_get_io_ptr(parPngPtr))
return;
PhysicsFSFile& rawfile = *static_cast<PhysicsFSFile*>(png_get_io_ptr(parPngPtr));
const int64_t read = rawfile.Read(static_cast<void*>(parOutBytes), static_cast<uint32_t>(parByteCountToRead), 1);
if (read != static_cast<int64_t>(parByteCountToRead))
return;
return;
}
///----------------------------------------------------------------------
///http://blog.hammerian.net/2009/reading-png-images-from-memory/
///----------------------------------------------------------------------
SDL_Surface* LoadNewPngSurface (const std::string& parPath) {
PhysicsFSFile rawfile(parPath.c_str(), PhysicsFSFile::OpenMode_Read, "graphics");
unsigned char header[8];
assert(rawfile.IsOpen());
rawfile.Read(header, 8, 1);
if (png_sig_cmp(header, 0, 8))
//Read the signature from the input stream
rawfile.Read(header, lengthof(header), 1);
if (png_sig_cmp(header, 0, lengthof(header)))
return nullptr;
png_structp pngptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (not pngptr)
return nullptr;
//Get the file info struct
png_structp pngptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (not pngptr)
return nullptr;
return nullptr;
//Get the data info struct
png_infop infoptr = png_create_info_struct(pngptr);
if (not infoptr) {
png_destroy_read_struct(&pngptr, nullptr, nullptr);
return nullptr;
}
//Set the function that will be called to read data from the stream
png_set_read_fn(pngptr, &rawfile, ReadDataFromInputStream);
//Tell the lib we already verified the signature
png_set_sig_bytes(pngptr, lengthof(header));
//Read the header
png_uint_32 width, height;
int bitDepth, colorType;
png_read_info(pngptr, infoptr);
const png_uint_32 headerGetInfoRetVal = png_get_IHDR(pngptr, infoptr, &width, &height, &bitDepth, &colorType, nullptr, nullptr, nullptr);
if (static_cast<png_uint_32>(-1) == headerGetInfoRetVal) {
png_destroy_read_struct(&pngptr, &infoptr, nullptr);
return nullptr;
}
SDL_Surface* retSurf;
switch (colorType) {
case PNG_COLOR_TYPE_RGB:
retSurf = nullptr; //SurfaceFromPngRGB();
assert(false); //not implemented
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
retSurf = SurfaceFromPngRGBA(ushort2(static_cast<uint8_t>(width), static_cast<uint8_t>(height)), bitDepth * 4, pngptr, infoptr);
break;
default:
png_destroy_read_struct(&pngptr, &infoptr, nullptr);
retSurf = nullptr;
}
return retSurf;
}
} //unnamed namespace
///------------------------------------------------------------------------
///------------------------------------------------------------------------
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
Texture::Texture (const std::string& parPath, SDLMain* parMain, bool parLoadNow) :
m_path(parPath),
m_texture(nullptr),
@ -74,14 +174,14 @@ namespace cloonel {
Reload();
}
///------------------------------------------------------------------------
///------------------------------------------------------------------------
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
Texture::~Texture() noexcept {
Destroy();
}
///------------------------------------------------------------------------
///------------------------------------------------------------------------
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void Texture::Destroy() noexcept {
if (m_texture) {
SDL_DestroyTexture(m_texture);
@ -89,8 +189,8 @@ namespace cloonel {
}
}
///------------------------------------------------------------------------
///------------------------------------------------------------------------
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void Texture::Reload() {
const GraphicFormat fmt = GuessGraphicFormatFromName(m_path);
Destroy();
@ -99,6 +199,7 @@ namespace cloonel {
switch (fmt) {
case GraphicFormat_Png:
surf = LoadNewPngSurface(m_path.c_str());
break;
default:
throw std::runtime_error(std::string("Unsupported file format for \"") + m_path + "\"");
@ -116,9 +217,9 @@ namespace cloonel {
}
}
///------------------------------------------------------------------------
///------------------------------------------------------------------------
void Texture::Render (const int2& parPos) {
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void Texture::Render (int2 parPos) const {
assert(IsLoaded());
const SDL_Rect dest = { parPos.x(), parPos.y(), m_size.x(), m_size.y() };
SDL_RenderCopy(m_sdlmain->GetRenderer(), m_texture, nullptr, &dest);

View file

@ -17,7 +17,7 @@ namespace cloonel {
void Reload ( void );
void Destroy ( void ) noexcept;
bool IsLoaded ( void ) const { return nullptr != m_texture; }
void Render ( const int2& parPos );
void Render ( int2 parPos ) const;
private:
const std::string m_path;