394 lines
11 KiB
C++
394 lines
11 KiB
C++
#include "Renderwindow.hpp"
|
|
#include "Values.hpp"
|
|
#include "Logger.hpp"
|
|
|
|
namespace Birb
|
|
{
|
|
Window::Window(std::string p_title, Vector2int p_window_dimensions, int p_refresh_rate, bool resizable)
|
|
:refresh_rate(p_refresh_rate), window_dimensions(p_window_dimensions), original_window_dimensions(p_window_dimensions), win_title(p_title)
|
|
{
|
|
/* Create a new window and initialize stuff for it */
|
|
InitSDL();
|
|
InitSDL_ttf();
|
|
InitSDL_image();
|
|
|
|
if (resizable)
|
|
win = SDL_CreateWindow(p_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, p_window_dimensions.x, p_window_dimensions.y, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
|
else
|
|
win = SDL_CreateWindow(p_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, p_window_dimensions.x, p_window_dimensions.y, SDL_WINDOW_SHOWN);
|
|
|
|
if (win == NULL)
|
|
Debug::Log("Window failed to init: " + (std::string)SDL_GetError(), Debug::error);
|
|
|
|
renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
|
|
|
|
/* Set some global rendering variables */
|
|
Global::RenderVars::RefreshRate = refresh_rate;
|
|
Global::RenderVars::MainWindow = win;
|
|
Global::RenderVars::Renderer = renderer;
|
|
}
|
|
|
|
void Window::InitSDL()
|
|
{
|
|
/* Check if SDL has already been initialized */
|
|
if (Global::IsInit::SDL)
|
|
return;
|
|
|
|
Debug::Log("Initializing SDL...");
|
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) > 0)
|
|
{
|
|
Debug::Log("SDL Init failed: " + (std::string)SDL_GetError(), Debug::error);
|
|
exit(2);
|
|
}
|
|
else
|
|
{
|
|
Global::IsInit::SDL = true;
|
|
}
|
|
}
|
|
|
|
void Window::InitSDL_ttf()
|
|
{
|
|
/* Check if SDL_ttf has already been initialized */
|
|
if (Global::IsInit::SDL_ttf)
|
|
return;
|
|
|
|
Debug::Log("Initializing SDL_ttf...");
|
|
if (TTF_Init() == -1)
|
|
{
|
|
Debug::Log("TTF_Init has failed: " + (std::string)TTF_GetError(), Debug::error);
|
|
exit(2);
|
|
}
|
|
else
|
|
{
|
|
Global::IsInit::SDL_ttf = true;
|
|
}
|
|
}
|
|
|
|
void Window::InitSDL_image()
|
|
{
|
|
/* Check if SDL_image has already been initialized */
|
|
if (Global::IsInit::SDL_image)
|
|
return;
|
|
|
|
Debug::Log("Initializing SDL_image...");
|
|
if (!(IMG_Init(IMG_INIT_PNG)))
|
|
{
|
|
Debug::Log("IMG_Init has failed" + (std::string)SDL_GetError(), Debug::error);
|
|
exit(2);
|
|
}
|
|
else
|
|
{
|
|
Global::IsInit::SDL_image = true;
|
|
}
|
|
}
|
|
|
|
void Window::Cleanup()
|
|
{
|
|
Global::IsInit::SDL = false;
|
|
Global::IsInit::SDL_image = false;
|
|
|
|
Debug::Log("Destroying the window");
|
|
SDL_DestroyWindow(win);
|
|
}
|
|
|
|
void Window::Clear()
|
|
{
|
|
/* Clear the window renderer. Call before rendering stuff */
|
|
SDL_RenderClear(Global::RenderVars::Renderer);
|
|
}
|
|
|
|
void Window::Display()
|
|
{
|
|
SDL_RenderPresent(Global::RenderVars::Renderer);
|
|
}
|
|
|
|
Vector2int Window::CursorPosition()
|
|
{
|
|
Vector2int pos;
|
|
SDL_GetMouseState(&pos.x, &pos.y);
|
|
return pos;
|
|
}
|
|
|
|
bool Window::CursorInRect(Rect rect)
|
|
{
|
|
Vector2int cursorPos = CursorPosition();
|
|
|
|
if (cursorPos.x > rect.x && cursorPos.x < rect.x + rect.w)
|
|
if (cursorPos.y > rect.y && cursorPos.y < rect.y + rect.h)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void Window::SetWindowSize(Vector2int dimensions)
|
|
{
|
|
SDL_SetWindowSize(win, dimensions.x, dimensions.y);
|
|
window_dimensions = dimensions;
|
|
window_dimensions_multiplier.x = (float)window_dimensions.x / (float)original_window_dimensions.x;
|
|
window_dimensions_multiplier.y = (float)window_dimensions.y / (float)original_window_dimensions.y;
|
|
}
|
|
|
|
void Window::EventTick(SDL_Event event, bool* GameRunning)
|
|
{
|
|
switch (event.type)
|
|
{
|
|
/* Handle window resizing */
|
|
case (SDL_WINDOWEVENT):
|
|
if (event.window.event == SDL_WINDOWEVENT_RESIZED)
|
|
SetWindowSize(Vector2int(event.window.data1, event.window.data2));
|
|
break;
|
|
|
|
case (SDL_QUIT):
|
|
Debug::Log("Quitting...");
|
|
*GameRunning = false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool Window::PollEvents()
|
|
{
|
|
return (SDL_PollEvent(&event) != 0);
|
|
}
|
|
|
|
SDL_Texture* Resources::LoadTexture(std::string p_filePath)
|
|
{
|
|
SDL_Texture* texture = NULL;
|
|
texture = IMG_LoadTexture(Global::RenderVars::Renderer, p_filePath.c_str());
|
|
|
|
if (texture == NULL)
|
|
Debug::Log("Failed to load texture [" + p_filePath + "]: " + (std::string)SDL_GetError(), Debug::error);
|
|
|
|
return texture;
|
|
}
|
|
|
|
TTF_Font* Resources::LoadFont(std::string p_filePath, int p_fontSize)
|
|
{
|
|
TTF_Font* font;
|
|
font = TTF_OpenFont(p_filePath.c_str(), p_fontSize);
|
|
|
|
if (!font)
|
|
{
|
|
Debug::Log("Error while loading font [" + p_filePath + "] TTF_Error: " + (std::string)TTF_GetError(), Debug::error);
|
|
}
|
|
|
|
return font;
|
|
}
|
|
|
|
Uint8* Resources::CopyTexturePixels(
|
|
SDL_Surface* surface, // surface to take pixels from
|
|
int* width,
|
|
int* height,
|
|
int* pitch)
|
|
{
|
|
Uint8* pixels = 0;
|
|
SDL_Surface* tmpSurface = 0;
|
|
SDL_Texture* texture = 0;
|
|
int sizeInBytes = 0;
|
|
void* tmpPixels = 0;
|
|
int tmpPitch = 0;
|
|
Uint32 pixelFormat = SDL_GetWindowPixelFormat(Global::RenderVars::MainWindow);
|
|
|
|
tmpSurface = SDL_ConvertSurfaceFormat(surface, pixelFormat, 0);
|
|
if (tmpSurface)
|
|
texture = SDL_CreateTexture(Global::RenderVars::Renderer, pixelFormat, SDL_TEXTUREACCESS_STREAMING, tmpSurface->w, tmpSurface->h);
|
|
|
|
if (texture)
|
|
{
|
|
if (width)
|
|
*width = tmpSurface->w;
|
|
|
|
if (height)
|
|
*height = tmpSurface->h;
|
|
|
|
if (pitch)
|
|
*pitch = tmpSurface->pitch;
|
|
|
|
sizeInBytes = tmpSurface->pitch * tmpSurface->h;
|
|
pixels = (Uint8*)malloc( sizeInBytes );
|
|
SDL_LockTexture(texture, 0, &tmpPixels, &tmpPitch);
|
|
memcpy(pixels, tmpSurface->pixels, sizeInBytes);
|
|
SDL_UnlockTexture(texture);
|
|
}
|
|
|
|
/* Cleanup stuff */
|
|
if (texture)
|
|
SDL_DestroyTexture(texture);
|
|
|
|
if (tmpSurface)
|
|
SDL_FreeSurface(tmpSurface);
|
|
|
|
return pixels;
|
|
}
|
|
|
|
|
|
SDL_Texture* Resources::TextSprite(std::string text, TTF_Font* font, SDL_Color& color)
|
|
{
|
|
/* Check if the arguments are valid */
|
|
if (font == nullptr)
|
|
{
|
|
Debug::Log("Tried to render text with invalid font!");
|
|
return NULL;
|
|
}
|
|
|
|
//SDL_Surface* surface = TTF_RenderText_Solid(font, text.c_str(), color);
|
|
SDL_Surface* surface = TTF_RenderText_Blended(font, text.c_str(), color);
|
|
if (surface == nullptr)
|
|
Debug::Log("Error creating SDL_Surface. Text: " + (std::string)text + ". SDL Error: " + (std::string)SDL_GetError(), Debug::error);
|
|
|
|
SDL_Texture* texture = SDL_CreateTextureFromSurface(Global::RenderVars::Renderer, surface);
|
|
if (texture == nullptr)
|
|
Debug::Log("Error creating texture from surface: " + (std::string)SDL_GetError(), Debug::error);
|
|
|
|
SDL_FreeSurface(surface);
|
|
return texture;
|
|
}
|
|
|
|
SDL_Texture* Resources::TextSprite(std::string text, TTF_Font* font, SDL_Color& color, SDL_Color& bgColor)
|
|
{
|
|
/* Check if the arguments are valid */
|
|
if (font == nullptr)
|
|
{
|
|
Debug::Log("Tried to render text with invalid font!");
|
|
return NULL;
|
|
}
|
|
|
|
SDL_Surface* surface = TTF_RenderText_Shaded(font, text.c_str(), color, bgColor);
|
|
if (surface == nullptr)
|
|
Debug::Log("Error creating SDL_Surface. Text: " + (std::string)text + ". SDL Error: " + (std::string)SDL_GetError(), Debug::error);
|
|
|
|
SDL_Texture* texture = SDL_CreateTextureFromSurface(Global::RenderVars::Renderer, surface);
|
|
if (texture == nullptr)
|
|
Debug::Log("Error creating texture from surface: " + (std::string)SDL_GetError(), Debug::error);
|
|
|
|
SDL_FreeSurface(surface);
|
|
return texture;
|
|
}
|
|
|
|
void Render::DrawEntity(Entity& entity)
|
|
{
|
|
if (entity.sprite == nullptr)
|
|
{
|
|
Debug::Log("Entity '" + entity.name + "' has no sprite to render", Debug::error);
|
|
return;
|
|
}
|
|
|
|
SDL_Rect src;
|
|
SDL_Rect dst;
|
|
Vector2int centerPoint;
|
|
|
|
/* Get texture data */
|
|
int texWidth;
|
|
int texHeight;
|
|
SDL_QueryTexture(entity.sprite, NULL, NULL, &texWidth, &texHeight);
|
|
|
|
if (entity.animationComponent.frameCount == 0)
|
|
{
|
|
src.x = 0;
|
|
src.y = 0;
|
|
src.w = texWidth;
|
|
src.h = texHeight;
|
|
|
|
dst.x = entity.rect.x;
|
|
dst.y = entity.rect.y;
|
|
dst.w = entity.rect.w * entity.localScale.x;
|
|
dst.h = entity.rect.h * entity.localScale.y;
|
|
}
|
|
else
|
|
{
|
|
/* Entity probably has an animation component */
|
|
//src.x = entity.animationComponent.curAtlasPosition.x;
|
|
//src.y = entity.animationComponent.curAtlasPosition.y;
|
|
Vector2int atlasPos = entity.getAtlasPosition(entity.animationComponent.frameIndex);
|
|
src.x = atlasPos.x;
|
|
src.y = atlasPos.y;
|
|
src.w = entity.animationComponent.spriteSize.x;
|
|
src.h = entity.animationComponent.spriteSize.y;
|
|
|
|
dst.x = entity.rect.x;
|
|
dst.y = entity.rect.y;
|
|
dst.w = src.w * entity.localScale.x;
|
|
dst.h = src.h * entity.localScale.y;
|
|
|
|
|
|
|
|
/* Set the current atlast position to the next frame */
|
|
if (entity.animationComponent.animationQueued || entity.animationComponent.loop)
|
|
{
|
|
if (entity.animationComponent.frameTimer.running && entity.animationComponent.frameTimer.ElapsedSeconds() >= (1.0 / entity.animationComponent.fps))
|
|
{
|
|
if (entity.animationComponent.frameIndex < entity.animationComponent.lastFrame)
|
|
{
|
|
entity.animationComponent.frameIndex++;
|
|
entity.animationComponent.frameTimer.Start();
|
|
}
|
|
}
|
|
else if (!entity.animationComponent.frameTimer.running)
|
|
{
|
|
/* Start the frame timer */
|
|
entity.animationComponent.frameTimer.Start();
|
|
}
|
|
|
|
if (entity.animationComponent.loop && entity.animationComponent.frameIndex >= entity.animationComponent.lastFrame)
|
|
{
|
|
entity.animationComponent.frameIndex = 0;
|
|
}
|
|
else if (entity.animationComponent.animationQueued && entity.animationComponent.frameIndex >= entity.animationComponent.lastFrame)
|
|
{
|
|
entity.animationComponent.frameIndex = entity.animationComponent.lastFrame;
|
|
entity.animationComponent.animationQueued = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
centerPoint = Vector2int(entity.rect.w / 2, entity.rect.h / 2);
|
|
SDL_Point center = { centerPoint.x, centerPoint.y };
|
|
//Debug::Log("Angle: " + std::to_string(entity.angle));
|
|
|
|
if (SDL_RenderCopyEx(Global::RenderVars::Renderer, entity.sprite, &src, &dst, entity.angle, ¢er, SDL_FLIP_NONE) < 0)
|
|
Debug::Log("Error rendering [" + entity.name + "]. Error: " + SDL_GetError(), Debug::error);
|
|
}
|
|
|
|
void Render::ResetDrawColor()
|
|
{
|
|
SDL_SetRenderDrawColor(Global::RenderVars::Renderer, 0, 0, 0, 255);
|
|
}
|
|
|
|
void Render::DrawRect(SDL_Color color, Rect dimensions)
|
|
{
|
|
SetRenderDrawColor(color);
|
|
SDL_Rect rectangle = dimensions.getSDLRect();
|
|
SDL_RenderFillRect(Global::RenderVars::Renderer, &rectangle);
|
|
ResetDrawColor();
|
|
}
|
|
|
|
void Render::DrawRect(SDL_Color color, Rect dimensions, int width)
|
|
{
|
|
DrawRect(color, Rect(dimensions.x, dimensions.y, dimensions.w, width)); /* Top */
|
|
DrawRect(color, Rect(dimensions.x, dimensions.y + dimensions.h - width, dimensions.w, width)); /* Bottom */
|
|
DrawRect(color, Rect(dimensions.x, dimensions.y, width, dimensions.h)); /* Left */
|
|
DrawRect(color, Rect(dimensions.x + dimensions.w - width, dimensions.y, width, dimensions.h)); /* Right */
|
|
}
|
|
|
|
void Render::DrawLine(SDL_Color color, Vector2int pointA, Vector2int pointB)
|
|
{
|
|
SetRenderDrawColor(color);
|
|
SDL_RenderDrawLine(Global::RenderVars::Renderer, pointA.x, pointA.y, pointB.x, pointB.y);
|
|
ResetDrawColor();
|
|
}
|
|
|
|
void Render::DrawCircle(SDL_Color color, Vector2int pos, int radius)
|
|
{
|
|
Uint32 uColor = (255<<24) + (int(color.b)<<16) + (int(color.g)<<8) + int(color.r);;
|
|
filledCircleColor(Global::RenderVars::Renderer, pos.x, pos.y, radius, uColor);
|
|
ResetDrawColor();
|
|
}
|
|
|
|
void Render::SetRenderDrawColor(SDL_Color color)
|
|
{
|
|
SDL_SetRenderDrawColor(Global::RenderVars::Renderer, color.r, color.g, color.b, color.a);
|
|
}
|
|
}
|