#include "stdafx.h"
#include <SDL.h>
#include <SDL_image.h>
#include <memory>
#include <vector>
#include <iostream>
bool _finish = false;
SDL_Window *_window;
SDL_Renderer *_renderer;
static const uint32 FRAME_DELAY = 30;
class ImageData {
public:
ImageData(const std::string &name)
{
std::string img_path = name + ".png";
this->image = IMG_LoadTexture(_renderer, img_path.c_str());
if (this->image == nullptr) {
throw std::string(SDL_GetError());
}
std::string mask0_path = name + "_m0.png";
this->masks.emplace_back(IMG_LoadTexture(_renderer, mask0_path.c_str()));
if (this->masks[0] == nullptr) {
throw std::string(SDL_GetError());
}
std::string mask1_path = name + "_m1.png";
this->masks.emplace_back(IMG_LoadTexture(_renderer, mask1_path.c_str()));
if (this->masks[1] == nullptr) {
throw std::string(SDL_GetError());
}
}
~ImageData()
{
SDL_DestroyTexture(this->image);
this->image = nullptr;
for (auto &mask : this->masks) {
SDL_DestroyTexture(mask);
mask = nullptr;
}
}
uint32 flags; ///< Flags of the image. @see ImageFlags
uint16 width = 0; ///< Width of the image.
uint16 height = 0; ///< Height of the image.
int16 xoffset; ///< Horizontal offset of the image.
int16 yoffset; ///< Vertical offset of the image.
SDL_Texture *image;
std::vector<SDL_Texture *> masks;
};
std::vector<std::unique_ptr<ImageData>> _sprites;
/** Returns true when event polling ending event happens */
bool HandleEvent()
{
SDL_Event event;
if (SDL_PollEvent(&event) != 1) return true;
switch (event.type) {
case SDL_USEREVENT:
return true;
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_q:
_finish = true;
return true;
default:
break;
}
return false;
case SDL_WINDOWEVENT:
default:
return false;
}
}
uint8 GetR(uint32 rgba)
{
return rgba >> 24;
}
uint8 GetG(uint32 rgba)
{
return rgba >> 16;
}
uint8 GetB(uint32 rgba)
{
return rgba >> 8;
}
uint8 GetA(uint32 rgba)
{
return rgba;
}
void DrawSprite(int x, int y, const std::vector<uint32> &cols)
{
auto &imd = _sprites[0];
int w, h;
SDL_QueryTexture(imd->image, nullptr, nullptr, &w, &h);
SDL_Rect rect = {x, y, w, h};
SDL_RenderCopy(_renderer, imd->image, NULL, &rect);
SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND);
for (size_t i = 0; i < imd->masks.size(); i++) {
auto &mask = imd->masks[i];
SDL_SetTextureColorMod(mask, GetR(cols[i]), GetG(cols[i]), GetB(cols[i]));
SDL_RenderCopy(_renderer, mask, nullptr, &rect);
}
}
void OnNewFrame(uint delay)
{
(void)delay;
DrawSprite(50, 50, {0x0000FF00, 0x00FF0000});
SDL_RenderPresent(_renderer);
}
void LoadSprite(const std::string &name)
{
_sprites.emplace_back(new ImageData(name));
}
int main()
{
SDL_CreateWindowAndRenderer(800, 600, SDL_WINDOW_RESIZABLE, &_window, &_renderer);
IMG_Init(IMG_INIT_PNG);
if (_window == nullptr || _renderer == nullptr) return 1;
try {
LoadSprite("icecream");
} catch(std::string& ex) {
std::cout << ex << std::endl;
}
SDL_SetRenderDrawColor(_renderer, 0, 0, 0, 255);
while(!_finish) {
uint start = SDL_GetTicks();
OnNewFrame(FRAME_DELAY);
for (;;) {
if (HandleEvent()) break;
}
if (_finish) break;
uint now = SDL_GetTicks();
if (now >= start) {
now -= start;
if (now < FRAME_DELAY) SDL_Delay(FRAME_DELAY - now); // Wait
}
}
}