I’m growing a sport that makes use of SDL2, SDL2 Picture & SDL2 TTF, whereas utilizing clang compiler beneath Linux.
When operating it in launch mode(compiler flags: -Wall -O3) there’s a fixed utilization of about 52MB, I’ve checked with Valgrind for reminiscence leaks and there are none.
Right here is my CMake file:
cmake_minimum_required(VERSION 3.7)
venture(InvasiveSpeciesCPP)
include_directories("${PROJECT_SOURCE_DIR}/embody")
file(COPY "${PROJECT_SOURCE_DIR}/property/" DESTINATION "property/")
file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/src/*.cpp")
add_executable(${PROJECT_NAME} apps/Essential.cpp ${SOURCES})
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARIES} ${SDL2IMAGE_LIBRARIES} ${SDL2TTF_LIBRARIES})
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
-Wall>
$<$<CXX_COMPILER_ID:MSVC>:
/W4>)
My Sport class:
#embody "Sport.h"
Sport::Sport(Configurations configurations) {
_graphics = std::make_unique<Graphics>(configurations.windowWidth,
configurations.windowHeight,
configurations.flags);
_gameState = std::make_unique<GameState>(configurations.windowWidth,
configurations.windowHeight);
_mouseInput = std::make_unique<MouseInput>(MouseInput{-1, -1, 0});
_fpsCounter = std::make_unique<FPSCounter>();
_worldWidth = configurations.worldWidth;
_worldHeight = configurations.worldHeight;
_fpsCap = configurations.fpsCap;
}
auto Sport::begin() -> void {
_fpsCounter->fpsInit();
gameLoop(_fpsCap);
}
auto Sport::convertStateToGraphicsMap()
-> std::vector<std::pair<TileType, SDL_Point>> {
std::vector<std::pair<TileType, SDL_Point>> convertedVector;
for (auto o : _gameState->getGameObjects()) {
convertedVector.push_back(
std::make_pair(o.getTileType(), SDL_Point{(int)o.getPosition().x,
(int)o.getPosition().y}));
}
std::remove_if(convertedVector.start(), convertedVector.finish(),
[this](std::pair<TileType, SDL_Point> o)
o.second.y - (int)_gameState->getCamera().y >
_graphics->getWindowHeight();
);
for (auto &o : convertedVector) {
o.second.x -= _gameState->getCamera().x;
o.second.y -= _gameState->getCamera().y;
}
return convertedVector;
}
auto Sport::checkForSDLQuitEvents() -> bool {
SDL_Event occasion;
whereas (SDL_PollEvent(&occasion)) {
change (occasion.sort) {
case SDL_QUIT:
std::cout << "closeRequested! quitingn";
return true;
}
}
return false;
}
auto Sport::validatePlayerPosition() -> void {
Vector2d<float> &playerPosition = _gameState->getPlayer()->getPosition();
if (playerPosition.x < 0) {
playerPosition.x = 0;
}
if (playerPosition.y < 0) {
playerPosition.y = 0;
}
if (playerPosition.x > _worldWidth) {
playerPosition.x = (float)_worldWidth;
}
if (playerPosition.y > _worldHeight) {
playerPosition.y = (float)_worldHeight;
}
}
auto Sport::handleMouseState(float fps) -> void {
_mouseInput->mouseState =
SDL_GetMouseState(&_mouseInput->mouseX, &_mouseInput->mouseY);
if (_mouseInput->mouseState & SDL_BUTTON(SDL_BUTTON_LEFT)) {
// printf("SDL_MOUSEBUTTONDOWNn");
auto halfWindowWidth = _graphics->getWindowWidth() / 2;
auto halfWindowHeight = _graphics->getWindowHeight() / 2;
_gameState->setCamera(
{_gameState->getPlayer()->getPosition().x - halfWindowWidth,
_gameState->getPlayer()->getPosition().y - halfWindowHeight});
_gameState->getPlayer()->onDestinationSelected(
{(float)_mouseInput->mouseX + _gameState->getCamera().x,
(float)_mouseInput->mouseY + _gameState->getCamera().y},
fps);
validatePlayerPosition();
}
}
auto Sport::gameLoop(float fpsCap) -> void {
float minFrameRateDelay = MILLISECOND_IN_SECOND / fpsCap;
whereas (true) {
// course of occasions
if (checkForSDLQuitEvents())
return;
_graphics->clearRender();
float averageFPS = _fpsCounter->getAverageFramesPerSecond();
handleMouseState(averageFPS);
_graphics->renderGrid(convertStateToGraphicsMap());
_graphics->renderText("FPS: " + std::to_string(averageFPS),
{255, 255, 0, 255}, 0, 0);
_graphics->presentRender();
if (fpsCap < averageFPS) {
SDL_Delay(minFrameRateDelay);
}
_fpsCounter->fpsThink();
}
}
auto Sport::loadMap(const char *filename) -> void {
int present, mx, my, mw, mh;
std::ifstream in(filename);
if (!in.is_open()) {
std::cout << "Didn't open map file." << std::endl;
return;
}
in >> mw;
in >> mh;
in >> mx;
in >> my;
for (int i = 0; i < mh; i++) {
for (int j = 0; j < mw; j++) {
if (in.eof()) {
std::cout << "Reached finish of map file too quickly." << std::endl;
return;
}
in >> present;
if (present != 0) {
GameObject tmp(DEFAULT_OBJECT_SIZE, 0, {0, 0}, HUMAN_FEMALE);
if (present == 2 || present == 4) {
}
_map.push_back(tmp);
}
}
}
in.shut();
}
Sport::~Sport() { std::cout << "Sport destructorn"; }
My Graphics class:
#embody "Graphics.h"
Graphics::Graphics(Uint32 windowWidth, Uint32 windowHeight, Uint32 flags)
: _windowWidth(windowWidth), _windowHeight(windowHeight), _flags(flags) {
if (initializeSdl()) {
_window = std::unique_ptr<SDL_Window, std::perform<void(SDL_Window *)>>(
createWindow(), SDL_DestroyWindow);
_renderer =
std::unique_ptr<SDL_Renderer, std::perform<void(SDL_Renderer *)>>(
createRenderer(), SDL_DestroyRenderer);
_textures = std::unique_ptr<
std::map<TileType, SDL_Texture *>,
std::perform<void(std::map<TileType, SDL_Texture *> *)>>(
loadAllTextures(), Graphics::destroyAllTextures);
_baseTile =
std::unique_ptr<RectAndTexture, std::perform<void(RectAndTexture *)>>(
createBaseRect(), destroyRectAndTexture);
_globalFont = std::unique_ptr<TTF_Font, std::perform<void(TTF_Font *)>>(
createRegularFont(), destroyFont);
std::cout << "Graphics createdn";
}
}
auto Graphics::initializeSdl() -> bool {
// try to initialize graphics and timer system
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
std::cout << "error initializing SDL: n" << SDL_GetError();
return false;
}
if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) {
std::cout << "couldn't initialize sdl2_image: n" << IMG_GetError();
return false;
}
if (TTF_Init() == -1) {
std::cout << "SDL_ttf couldn't initialize! SDL_ttf Error: n"
<< TTF_GetError();
return false;
}
return true;
}
auto Graphics::createWindow() -> SDL_Window * {
SDL_Window *window = SDL_CreateWindow(
"InvasiveSpecies", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
_windowWidth, _windowHeight, _flags);
if (!window) {
std::cout << "error creating window: n" << SDL_GetError();
SDL_Quit();
return nullptr;
}
return window;
}
auto Graphics::createRenderer() -> SDL_Renderer * {
// create a renderer, which units up the graphics {hardware}
Uint32 render_flags = SDL_RENDERER_ACCELERATED;
SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, render_flags);
if (!renderer) {
std::cout << "error creating renderer: n" << SDL_GetError();
quitSdl();
return nullptr;
}
return renderer;
}
auto Graphics::loadTexture(const char *imagePath) -> SDL_Texture * {
SDL_Texture *texture = IMG_LoadTexture(_renderer.get(), imagePath);
if (!texture) {
std::cout << "error creating texturen";
quitSdl();
return nullptr;
}
return texture;
}
auto Graphics::createRectFromTexture(SDL_Texture *texture) -> RectAndTexture * {
auto *dest = new SDL_Rect();
SDL_QueryTexture(texture, nullptr, nullptr, &dest->w, &dest->h);
auto *rectAndTexture = new RectAndTexture{dest, texture};
return rectAndTexture;
}
auto Graphics::createBaseRect() -> RectAndTexture * {
RectAndTexture *baseTile = createRectFromTexture((*_textures)[SOIL]);
return baseTile;
}
auto Graphics::clearRender() -> void { SDL_RenderClear(_renderer.get()); }
auto Graphics::presentRender() -> void { SDL_RenderPresent(_renderer.get()); }
auto Graphics::renderGrid(
const std::vector<std::pair<TileType, SDL_Point>> &gameObjectsPositionsMap)
-> void {
renderGridBackground();
renderGameObjects(gameObjectsPositionsMap);
}
auto Graphics::renderGameObjects(
const std::vector<std::pair<TileType, SDL_Point>> &gameObjectsPositionsMap)
-> void {
for (const auto &present : gameObjectsPositionsMap) {
_baseTile->texture = (*_textures)[current.first];
_baseTile->rect->x = present.second.x;
_baseTile->rect->y = present.second.y;
renderTexture(_baseTile.get());
}
}
auto Graphics::renderGridBackground() -> void {
// printf("renderGridBackgroundn");
int tileWidth = _baseTile->rect->w;
int tileHeight = _baseTile->rect->h;
_baseTile->texture = (*_textures)[SOIL];
for (int i = 0; i < _windowWidth; i += tileWidth) {
for (int j = 0; j < _windowHeight; j += tileHeight) {
_baseTile->rect->x = i;
_baseTile->rect->y = j;
renderTexture(_baseTile.get());
}
}
}
auto Graphics::renderTexture(RectAndTexture *rectAndTexture) -> void {
SDL_RenderCopy(_renderer.get(), rectAndTexture->texture, nullptr,
rectAndTexture->rect);
}
auto Graphics::getImagePathStringByTileType(TileType tileType) -> const char * {
change (tileType) {
case TileType::SOIL:
return SOIL_IMAGE_PATH;
case TileType::GRASS:
return GRASS_IMAGE_PATH;
case TileType::STONES:
return STONES_IMAGE_PATH;
case TileType::HUMAN_MALE:
return HUMAN_MALE_IMAGE_PATH;
case TileType::HUMAN_FEMALE:
return HUMAN_FEMALE_IMAGE_PATH;
default:
break;
}
return nullptr;
}
auto Graphics::loadAllTextures() -> std::map<TileType, SDL_Texture *> * {
auto texturesMap = new std::map<TileType, SDL_Texture *>();
for (auto currentTileType : tileTypeVector) {
(*texturesMap)[currentTileType] =
loadTexture(getImagePathStringByTileType(currentTileType));
}
return texturesMap;
}
auto Graphics::destroyAllTextures(
std::map<TileType, SDL_Texture *> *texturesMap) -> void {
for (auto const &p : *texturesMap) {
SDL_DestroyTexture(p.second);
}
texturesMap->clear();
delete texturesMap;
std::cout << "destroyAllTextures donen";
}
auto Graphics::destroyFont(TTF_Font *font) -> void {
TTF_CloseFont(font);
std::cout << "destroyFont donen";
}
auto Graphics::destroyRectAndTexture(RectAndTexture *rectAndTexture) -> void {
delete rectAndTexture->rect;
// SDL_DestroyTexture(rectAndTexture->texture); //already freed at
// destroyAllTextures()
delete rectAndTexture;
}
auto Graphics::renderText(const std::string &textureText, SDL_Color textColor,
int x, int y) -> void {
SDL_Surface *textSurface =
TTF_RenderText_Solid(_globalFont.get(), textureText.c_str(), textColor);
SDL_Texture *textTexture = nullptr;
if (textSurface == nullptr) {
std::cout << "Unable to render textual content floor! SDL_ttf Error: n",
TTF_GetError();
} else {
// Create texture from floor pixels
textTexture = SDL_CreateTextureFromSurface(_renderer.get(), textSurface);
if (textTexture == nullptr) {
std::cout << "Unable to create texture from rendered textual content! SDL Error: n"
<< SDL_GetError();
} else {
std::unique_ptr<RectAndTexture, std::perform<void(RectAndTexture *)>>
baseTile = std::unique_ptr<RectAndTexture,
std::perform<void(RectAndTexture *)>>(
createRectFromTexture(textTexture), destroyRectAndTexture);
baseTile->rect->x = x;
baseTile->rect->y = y;
renderTexture(baseTile.get());
baseTile.reset();
SDL_DestroyTexture(textTexture);
}
// Eliminate outdated floor
SDL_FreeSurface(textSurface);
}
}
auto Graphics::getFontFromFile(const char *file, int ptsize) -> TTF_Font * {
TTF_Font *gFont = TTF_OpenFont(file, ptsize);
if (gFont == nullptr) {
std::cout << "Didn't load lazy font! SDL_ttf Error: n"
<< TTF_GetError();
}
return gFont;
}
auto Graphics::createRegularFont() -> TTF_Font * {
return getFontFromFile(FONT_PATH, FONT_SIZE);
}
auto Graphics::quitSdl() -> void {
// these have to be right here or else they may get known as after SDL_Quit()
_globalFont.reset();
_textures.reset();
_baseTile.reset();
_renderer.reset();
_window.reset();
TTF_Quit();
IMG_Quit();
SDL_Quit();
}
Graphics::~Graphics() {
std::cout << "Graphics destructorn";
quitSdl();
}
The property for the sport comprises .png and .tff recordsdata with a complete dimension of about 34KiB.
The remainder of the code is in My GitHub repo
Is the utilization of about 50MB RAM at runtime is regular beneath these situations?