C++ SDL2: How to render rects into multiple viewports - c++

I am new into SDL2(version 2.0.10) and I teach it from Lazy Foo tutorial. In Lesson of The ViewPort example code render me only first image in left viewport and others not. Render of rects in different viewports don't work either. What I am doing wrong when I want render rects in different viewports like this:
while( !quit ){
while( SDL_PollEvent( &e ) != 0 ){
if( e.type == SDL_QUIT ){
quit = true;
}
}
//Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );
//Top left corner viewport
SDL_Rect topLeftViewport;
topLeftViewport.x = 0;
topLeftViewport.y = 0;
topLeftViewport.w = SCREEN_WIDTH / 2;
topLeftViewport.h = SCREEN_HEIGHT / 2;
SDL_RenderSetViewport( gRenderer, &topLeftViewport );
SDL_Rect fillRect = { 10, 10, 100, 100 };
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0x00, 0x00, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect );
SDL_Rect topRightViewport;
topRightViewport.x = SCREEN_WIDTH / 2;
topRightViewport.y = 0;
topRightViewport.w = SCREEN_WIDTH / 2;
topRightViewport.h = SCREEN_HEIGHT / 2;
SDL_RenderSetViewport( gRenderer, &topRightViewport );
SDL_Rect fillRect2 = { 10, 10, 100, 100 };
SDL_SetRenderDrawColor( gRenderer, 0x00, 0xFF, 0x00, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect2 );
SDL_RenderPresent( gRenderer );
}

As I saw, you are drawing a rect at 10, 10 of 100x100 two times, this coordinates doesn't take account of the viewport coordinates. And in a way, if you want to do this by changing the viewport clipping is not relevant... just draw the square where you want.
UPDATE: I tried multiples viewports. Here is a working example. You can choose between the renderer (with viewports) or the classic way.
main.cpp :
#include "Application.hpp"
int
main (int argc, char * argv[])
{
Application app("SDL 2 Test", 800, 600, true);
return app.mainLoop();
}
Application.hpp :
#ifndef APPLICATION_HPP
#define APPLICATION_HPP
#include <SDL2/SDL.h>
class Application
{
public:
Application (const char * title = "UnknownApplication", int baseWidth = 640, int baseHeight = 480, bool useRenderer = false) noexcept;
~Application ();
int mainLoop () noexcept;
private:
int m_width = 0;
int m_height = 0;
SDL_Window * m_window = nullptr;
SDL_Renderer * m_renderer = nullptr;
bool m_useRenderer = false;
bool m_isRunning = false;
};
#endif /* APPLICATION_HPP */
Application.cpp :
#include "Application.hpp"
#include <iostream>
#include <SDL2/SDL_image.h>
Application::Application (const char * title, int baseWidth, int baseHeight, bool useRenderer) noexcept
: m_width(baseWidth), m_height(baseHeight), m_useRenderer(useRenderer)
{
if ( SDL_Init(SDL_INIT_VIDEO) != 0 )
{
std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
return;
}
m_window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, m_width, m_height, SDL_WINDOW_SHOWN);
if ( m_window == nullptr )
{
std::cerr << "Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
return;
}
if ( m_useRenderer )
{
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE);
if ( m_renderer == nullptr )
{
std::cerr << "Renderer could not be created! SDL_Error: " << SDL_GetError() << std::endl;
return;
}
}
m_isRunning = true;
}
int
Application::mainLoop () noexcept
{
SDL_Event event;
const auto filepath = "SET_IMAGE_YOU_WANT_HERE";
auto surface = IMG_Load(filepath);
if ( surface == nullptr )
{
std::cerr << "Unable to read image file : " << filepath << std::endl;
return 1;
}
SDL_Rect logoPosition = {8, 8, 32, 32};
if ( m_useRenderer )
{
auto texture = SDL_CreateTextureFromSurface(m_renderer, surface);
SDL_Rect screenA = {0, 0, m_width / 2, m_height / 2};
SDL_Rect screenB = {m_width / 2, 0, m_width / 2, m_height / 2};
while ( m_isRunning )
{
while ( SDL_PollEvent(&event) != 0 )
{
if ( event.type == SDL_QUIT )
m_isRunning = false;
}
SDL_SetRenderDrawColor(m_renderer, 0, 0, 0, 255);
SDL_RenderClear(m_renderer);
SDL_RenderSetViewport(m_renderer, &screenA);
SDL_SetRenderDrawColor(m_renderer, 255, 0, 0, 255);
SDL_RenderFillRect(m_renderer, nullptr);
SDL_RenderCopy(m_renderer, texture, nullptr, &logoPosition);
SDL_RenderSetViewport(m_renderer, &screenB);
SDL_SetRenderDrawColor(m_renderer, 0, 255, 0, 255);
SDL_RenderFillRect(m_renderer, nullptr);
SDL_RenderCopy(m_renderer, texture, nullptr, &logoPosition);
SDL_RenderPresent(m_renderer);
}
SDL_DestroyTexture(texture);
}
else
{
auto windowSurface = SDL_GetWindowSurface(m_window);
while ( m_isRunning )
{
while ( SDL_PollEvent(&event) != 0 )
{
if ( event.type == SDL_QUIT )
m_isRunning = false;
}
SDL_FillRect(windowSurface, nullptr, SDL_MapRGB(windowSurface->format, 0xFF, 0x00, 0xFF));
//SDL_BlitSurface(surface, nullptr, windowSurface, &logoPosition);
SDL_BlitScaled(surface, nullptr, windowSurface, &logoPosition);
SDL_UpdateWindowSurface(m_window);
}
}
SDL_FreeSurface(surface);
return 0;
}
Application::~Application (void)
{
if ( m_renderer != nullptr )
SDL_DestroyRenderer(m_renderer);
if ( m_window != nullptr )
SDL_DestroyWindow(m_window);
SDL_Quit();
}

Related

SDL_ttf display glitches

I'm trying to display the string "hey" using a true type font in SDL, but there are glitches. Here is the text as it should appear (I took a screen recording, so the lower part in this shot is just the control for the video player):
And here it is with a glitch:
As you can see the upper part of the letter "h" is missing.
Here is the code that I used:
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <iostream>
#include <string>
int fatal( std::string m ) {
std::cout << "Fatal error: " << m << "\n";
exit(-1);
}
void drawText(TTF_Font* font,SDL_Renderer* r, std::string message) {
SDL_Color c = {255,255,255,255};
SDL_Surface *temp = TTF_RenderText_Blended( font, message.c_str(), c);
if ( temp == NULL )
fatal("failed to create surface");
SDL_Texture *txt = SDL_CreateTextureFromSurface( r, temp );
if ( txt == NULL )
fatal("failed to create texture");
SDL_FreeSurface( temp );
SDL_Rect src;
src.x = 0;
src.y = 0;
SDL_QueryTexture( txt, NULL, NULL, &src.w, &src.h );
SDL_Rect pos;
pos.x = 80;
pos.y = 80;
pos.w = src.w;
pos.h = src.h;
if ( SDL_RenderCopy(r,txt,&src,&pos) != 0)
fatal("SDL_RenderCopy failed");
SDL_DestroyTexture(txt);
}
extern "C" int main( int argc, char** argv ) {
SDL_Renderer *renderer;
SDL_Window *window;
if ( SDL_Init( SDL_INIT_VIDEO ) != 0 )
fatal("sdl_init failed");
if ( TTF_Init() != 0 )
fatal("ttf_init failed");
if ( SDL_CreateWindowAndRenderer ( 200, 200, 0, &window, &renderer ) != 0 )
fatal("sdl_createwindowandrenderer failed");
TTF_Font* font = TTF_OpenFont( "Arial.ttf", 30 );
if ( font == NULL )
fatal("failed to open font");
SDL_Event e;
while ( 1 ) {
if ( SDL_PollEvent(&e) ) {
if (e.type == SDL_QUIT)
break;
}
// clear back buffer
SDL_SetRenderDrawColor(renderer,0,0,255,255);
SDL_RenderClear(renderer);
drawText(font,renderer,"hey");
SDL_RenderPresent(renderer);
}
return 0;
}
Which I compiled on macOS 10.15.6 using the following command
g++ -std=c++17 textTest.cpp -lSDL2 -lSDL2_ttf

SDL_GetKeyboardState(NULL) isn't working as expected

I am making a pong clone in C++/SDL2. To take keyboard input from multiple keys, I would like to use SDL_GetKeyboardState(NULL) with a Uint8. However, it isn't working as expected.
Expected behavior: pong paddles move up and down with each keypress.
Actual behavior: keys are not registered.
Here is my code (note that variables written in uppercase letters are from variables.h):
// g++ main.cpp `pkg-config sdl2 SDL2_ttf --cflags --libs`
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <iostream> // For io
#include <time.h> // Rand seeder
const bool debug = true;
// Basic stuff needed for SDL2
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
const int WINDOW_CENTER_X = WINDOW_WIDTH / 2;
const int WINDOW_CENTER_Y = WINDOW_HEIGHT / 2;
const char* WINDOW_TITLE = "Pong";
// Define the location of the paddles in the bitmap
const int PADDLE_BITMAP_X = 0;
const int PADDLE_BITMAP_Y = 0;
const int BALL_BITMAP_X = 100;
const int BALL_BITMAP_Y = 0;
// Positions of player 1 and player 2
const int PADDLE1_X = 50;
const int PADDLE2_X = WINDOW_WIDTH - 75;
// Paddle width and height
const int PADDLE_WIDTH = 20;
const int PADDLE_HEIGHT = 100;
// Speed of both players
const int PLAYER_SPEED = 0;
// Ball Speed -- this will not be constant
// The Ball Modifier will modify the speed based on the place it lands on the paddle
// Ball speed will never go under 10, and will accelerate over time
// Ball diameter
const int BALL_SPEED = 100;
const int BALL_MODIFIER = 5;
const int BALL_DIAMETER = 10;
const int BALL_CENTER_X = WINDOW_CENTER_X - BALL_DIAMETER;
const int BALL_CENTER_Y = WINDOW_CENTER_Y - BALL_DIAMETER;
const int LANG = 3;
const int LANG_ENGLISH = 3;
const int LANG_GERMAN = 4;
// Game Entity data structure
struct GameObject
{
SDL_Rect ScreenLocation;
SDL_Rect BitmapLocation;
int SpeedX;
int SpeedY;
};
// SDL stuff
SDL_Window* gWindow = NULL;
SDL_Renderer* gWindowRenderer;
SDL_Rect gScreen;
SDL_Event e;
// Game objects
GameObject gPlayer1; // Paddle 1
GameObject gPlayer2; // Paddle 2
GameObject gBall; // Ball
// Scores. I feel like it's better to leave them uninitialized.
int gPlayer1Score;
int gPlayer2Score;
void Render();
bool init();
bool GameQuit;
void Quit();
int main( int argc, char* argv[] )
{
// const Uint8* keyStates = SDL_GetKeyboardState(NULL);
if( init() == false )
{
std::cout << "Init failed. Bye bye!\n";
return 1;
}
while( !GameQuit )
{
const Uint8* keyStates = SDL_GetKeyboardState( NULL );
while( SDL_PollEvent( &e ) )
{
if( e.type == SDL_QUIT )
GameQuit = true;
if( e.type == SDL_KEYDOWN )
{
switch( e.key.keysym.scancode )
{
case SDL_SCANCODE_ESCAPE:
GameQuit = true;
break;
}
}
}
if( keyStates[ SDL_SCANCODE_UP ] )
{
gPlayer1.ScreenLocation.y -= PLAYER_SPEED;
}
if( keyStates[ SDL_SCANCODE_DOWN ] )
{
gPlayer1.ScreenLocation.y += PLAYER_SPEED;
}
if( keyStates[ SDL_SCANCODE_W ] )
{
gPlayer2.ScreenLocation.y -= PLAYER_SPEED;
}
if( keyStates[ SDL_SCANCODE_S ] )
{
gPlayer2.ScreenLocation.y += PLAYER_SPEED;
}
Render();
}
Quit();
return 0;
}
bool init()
{
bool success = true;
if( SDL_Init( SDL_INIT_VIDEO < 0 ) )
{
success = false;
return success;
}
if( TTF_Init() < 0 )
{
success = false;
return success;
}
srand( time( NULL ) ); // Seed rng
// From SDL_Rect.h
// 64 typedef struct SDL_Rect
// 65 {
// 66 int x, y;
// 67 int w, h;
// 68 } SDL_Rect;
GameQuit = false;
gPlayer1.ScreenLocation.y = ( ( WINDOW_HEIGHT / 2 ) - ( PADDLE_HEIGHT / 2 ) );
gPlayer1.ScreenLocation.x = PADDLE1_X;
gPlayer1.ScreenLocation.w = PADDLE_WIDTH;
gPlayer1.ScreenLocation.h = PADDLE_HEIGHT;
gPlayer2.ScreenLocation.y = ( ( WINDOW_HEIGHT / 2 ) - ( PADDLE_HEIGHT / 2 ) );
gPlayer2.ScreenLocation.x = PADDLE2_X;
gPlayer2.ScreenLocation.w = PADDLE_WIDTH;
gPlayer2.ScreenLocation.h = PADDLE_HEIGHT;
gBall.ScreenLocation.x = BALL_CENTER_X;
gBall.ScreenLocation.y = BALL_CENTER_Y;
gBall.ScreenLocation.w = BALL_DIAMETER;
gBall.ScreenLocation.h = BALL_DIAMETER;
gPlayer1.BitmapLocation.x = PADDLE_BITMAP_X;
gPlayer1.BitmapLocation.y = PADDLE_BITMAP_Y;
gPlayer1.BitmapLocation.w = PADDLE_WIDTH;
gPlayer1.BitmapLocation.h = PADDLE_HEIGHT;
gPlayer2.BitmapLocation.x = PADDLE_BITMAP_X;
gPlayer2.BitmapLocation.y = PADDLE_BITMAP_Y;
gPlayer2.BitmapLocation.w = PADDLE_WIDTH;
gPlayer2.BitmapLocation.h = PADDLE_HEIGHT;
gBall.BitmapLocation.x = BALL_BITMAP_X;
gBall.BitmapLocation.y = BALL_BITMAP_Y;
gBall.BitmapLocation.w = BALL_DIAMETER;
gBall.BitmapLocation.h = BALL_DIAMETER;
gPlayer1.SpeedY = PLAYER_SPEED;
gPlayer1.SpeedX = 0;
gPlayer2.SpeedY = PLAYER_SPEED;
gPlayer2.SpeedX = 0;
gPlayer1Score = 0;
gPlayer2Score = 0;
gScreen.x = 0;
gScreen.y = 0;
gScreen.w = WINDOW_WIDTH;
gScreen.h = WINDOW_HEIGHT;
// Note to self: Leave this out since color keying NULL will segfault.
// SDL_SetColorKey(gBitmap, SDL_TRUE, SDL_MapRGB(gBitmap->format, 255, 0, 255));
gWindow = SDL_CreateWindow(
WINDOW_TITLE,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
WINDOW_WIDTH,
WINDOW_HEIGHT,
SDL_WINDOW_MAXIMIZED );
// Render SDL Window
gWindowRenderer = SDL_CreateRenderer( gWindow, -1, 0 );
if( gWindowRenderer == nullptr )
{
success = false;
return success;
}
SDL_RenderSetLogicalSize( gWindowRenderer, WINDOW_WIDTH, WINDOW_HEIGHT );
SDL_SetRenderDrawColor( gWindowRenderer, 0x00, 0x00, 0x00, 0xFF );
return success;
}
// Display Menu Text
bool Menu()
{
bool success = false;
if( LANG == LANG_ENGLISH )
{
// DisplayText("Start (G)ame", 350, 250, 12, 255, 255, 255);
// DisplayText("(Q)uit Game", 350, 270, 12, 255, 255, 255);
success = true;
return success;
}
else if( LANG == LANG_GERMAN )
{
// DisplayText("(G) Spielen", 350, 270, 12, 255, 255, 255);
// DisplayText("(Q) Spiel verlassen", 350, 270, 12, 255, 255, 255);
success = true;
return success;
}
else
{
return success;
}
}
void Render()
{
SDL_RenderClear( gWindowRenderer );
SDL_SetRenderDrawColor( gWindowRenderer, 0x00, 0x00, 0x00, 0xFF );
SDL_RenderFillRect( gWindowRenderer, &gScreen );
SDL_SetRenderDrawColor( gWindowRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderFillRect( gWindowRenderer, &gPlayer1.ScreenLocation );
SDL_RenderFillRect( gWindowRenderer, &gPlayer2.ScreenLocation );
SDL_RenderFillRect( gWindowRenderer, &gBall.ScreenLocation );
SDL_RenderPresent( gWindowRenderer );
}
void Quit()
{
SDL_DestroyWindow( gWindow );
SDL_Quit();
}
I'm not sure what I'm doing wrong and would appreciate a concise answer.
Thank you for your time.
Builds & runs fine on my Debian 10 system, though PLAYER_SPEED is zero so nothing useful happens to gPlayer1.ScreenLocation.y/gPlayer2.ScreenLocation.y in the keyStates if-blocks.
Setting PLAYER_SPEED to something other than zero fixes that on my end.

SDL2 Getting weird colors

I'm creating a simple tile-based game using SDL2. I've drawn my tiles on two layers. The problem is the second layer which as you can see with the image below for some reason tiles with something already drawn underneath have a reddish tint. The corner and side tiles for the grass should be exactly the same color, for example.
Here's an image of my problem:
Here's my tilesheet:
And here is my code:
#include <iostream>
#include <string>
#include <SDL.h>
#include <SDL_image.h>
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 640;
//The window we'll be rendering to
SDL_Window* window = NULL;
//The surface contained by the window
SDL_Surface* screenSurface = NULL;
//Holds built base layer of tilemap.
SDL_Surface* baseLayer = NULL;
//Map Data array
char mapLayerOne[20][20] = {
{4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },
{4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },
{4,4,4,6,6,6,6,6,6,4,4,4,4,4,4,4,4,4,4,4 },
{4,4,4,6,8,8,6,6,6,6,6,6,6,4,4,4,4,4,4,4 },
{4,4,4,6,8,8,6,6,6,6,6,6,6,4,4,4,4,4,4,4 },
{4,4,4,6,6,8,6,6,6,6,6,6,6,4,4,4,4,4,4,4 },
{4,4,4,6,6,8,8,8,8,6,6,6,6,6,4,4,4,4,4,4 },
{4,4,4,6,6,6,6,6,8,6,6,6,6,6,6,4,4,4,4,4 },
{4,4,4,6,6,14,6,6,8,8,6,6,6,6,6,4,4,4,4,4 },
{4,4,4,6,14,16,14,6,6,8,6,6,6,6,6,4,4,4,4,4 },
{4,4,4,14,16,16,16,12,8,8,8,8,6,6,6,4,4,4,4,4 },
{4,4,4,6,16,16,16,6,6,6,6,8,8,8,6,4,4,4,4,4 },
{4,4,4,6,6,16,6,6,6,6,6,6,6,8,6,4,4,4,4,4 },
{4,4,13,6,6,6,6,6,6,6,6,6,6,8,6,4,4,4,4,4 },
{4,4,4,14,14,14,14,14,14,14,14,14,14,14,14,15,4,4,4,4 },
{4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },
{4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },
{4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },
{4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,4,4,4,4 },
{4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,4,4,4,4 }
};
char mapLayerTwo[20][20] = {
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,1,2,2,2,2,2,3,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,0,5,0,0,0,0,0,0,2,2,2,2,3,0,0,0,0,0,0 },
{ 0,0,5,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0 },
{ 0,0,5,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0 },
{ 0,0,5,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0 },
{ 0,0,5,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0 },
{ 0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0 },
{ 0,0,5,0,0,10,0,0,0,0,0,0,0,0,0,7,0,0,0,0 },
{ 0,0,5,0,11,18,9,0,0,0,0,0,0,0,0,7,0,0,0,0 },
{ 0,0,5,7,19,0,12,12,0,0,0,0,0,0,0,7,0,0,0,0 },
{ 0,0,5,0,3,0,1,0,0,0,0,0,0,0,0,7,0,0,0,0 },
{ 0,0,5,0,0,2,0,0,0,0,0,0,0,0,0,7,0,0,0,0 },
{ 0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0 },
{ 0,0,17,9,10,10,10,10,10,10,10,10,10,12,10,11,0,0,0,0 },
{ 0,0,0,17,18,18,18,18,18,18,18,18,18,12,18,19,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,1,2,12,2,3,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,0,5,0,8,0,0,3,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0,1,0,0,8,0,0,7,0,0,0 }
};
bool init();
void DrawTiles(SDL_Surface *image, char mapLayer);
int main(int argc, char* args[])
{
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
if(init())
{
//Load images
SDL_Surface *image = IMG_Load("Images/TileSheet_01.png");
if (!image)
std::cout << "Failed to load TileSheet_01.png!" << std::endl;
//Create BaseLayers of map
DrawTiles(image, 1);
DrawTiles(image, 2);
//While application is running
while (!quit)
{
//Handle events on queue
while (SDL_PollEvent(&e) != 0)
{
//User requests quit
if (e.type == SDL_QUIT)
quit = true;
}
//Get window surface
screenSurface = SDL_GetWindowSurface(window);
//Blit base layer of map to screenSurface
SDL_BlitSurface(baseLayer, NULL, screenSurface, NULL);
//Update the surface
SDL_UpdateWindowSurface(window);
//Delay in milliseconds to improve performance
SDL_Delay(1);
}
}
//Destroy window
SDL_DestroyWindow(window);
//Quit SDL subsystems
SDL_Quit();
return 0;
}
void DrawTiles(SDL_Surface *image, char mapLayer)
{
SDL_Rect baseTile[20];
int tileX = 0;
int tileY = 0;
for (int i = 1; i < 20; i++)
{
baseTile[i].h = 32;
baseTile[i].w = 32;
baseTile[i].x = tileX;
baseTile[i].y = tileY;
tileX += 32;
if (tileX == 128) { tileY += 32; tileX = 0; }
}
//Fill the surface
SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 150, 50, 50));
SDL_Rect tileLoc;
tileLoc.x = 0;
tileLoc.y = 0;
// Draw tiles
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if (mapLayer == 1 && mapLayerOne[i][j] != 0)
SDL_BlitSurface(image, &baseTile[mapLayerOne[i][j]], baseLayer, &tileLoc);
else if (mapLayer == 2 && mapLayerTwo[i][j] != 0)
SDL_BlitSurface(image, &baseTile[mapLayerTwo[i][j]], baseLayer, &tileLoc);
tileLoc.x += 32;
if (tileLoc.x == 640)
{
tileLoc.x = 0;
tileLoc.y += 32;
}
}
}
}
bool init()
{
//Initialization flag
bool success = true;
//Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
std::cout << "SDL could not initialize!" << std::endl;
success = false;
}
else
{
//Create window
window = SDL_CreateWindow("My SDL TileMap", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (window == NULL)
{
std::cout << "Window could not be created!" << std::endl;
success = false;
}
else
{
//Initialize PNG loading
int imgFlags = IMG_INIT_PNG;
if (!(IMG_Init(imgFlags) & imgFlags))
{
//std::cout << "SDL_image could not initialize!" << std::endl;
printf("SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError());
success = false;
}
else
{
//Get window surface
screenSurface = SDL_GetWindowSurface(window);
//Surface to hold baselayer of map.
baseLayer = SDL_CreateRGBSurface(0, SCREEN_WIDTH, SCREEN_HEIGHT, 16, 0, 0, 0, 0);
}
}
}
SDL_Delay(300);
return success;
}
What's causing this?
baseLayer = SDL_CreateRGBSurface( 0, SCREEN_WIDTH, SCREEN_HEIGHT, 16, 0, 0, 0, 0 );
^^ ...but you're using 32bpp PNGs
Use a 32-bit surface instead of 16 and populate the masks:
// https://wiki.libsdl.org/SDL_CreateRGBSurface#Code_Examples
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
const Uint32 rmask = 0xff000000;
const Uint32 gmask = 0x00ff0000;
const Uint32 bmask = 0x0000ff00;
const Uint32 amask = 0x000000ff;
#else
const Uint32 rmask = 0x000000ff;
const Uint32 gmask = 0x0000ff00;
const Uint32 bmask = 0x00ff0000;
const Uint32 amask = 0xff000000;
#endif
baseLayer = SDL_CreateRGBSurface( 0, SCREEN_WIDTH, SCREEN_HEIGHT, 32, rmask, gmask, bmask, amask );

IMG_Load doesn't work

I was watching this series = https://www.youtube.com/watch?v=2NVgHrOFneg
and for some reason for the guy in the video the code works but for me it compiles fine but doesn't load an image. I really don't know what to do.
#include "SDL.h"
#include <iostream>
#include "SDL_image.h"
SDL_Texture *LoadTexture(std::string filePath, SDL_Renderer *renderTarget) //texture optimization function
{
SDL_Texture *texture = nullptr;
SDL_Surface *surface = IMG_Load(filePath.c_str());
if (surface == NULL)
std::cout << "Error 1" << std::endl;
else
{
texture = SDL_CreateTextureFromSurface(renderTarget, surface);
if (texture == NULL)
std::cout << "Error 2" << std::endl;
}
SDL_FreeSurface(surface);
return texture;
}
int main(int, char *argv[])
{
const int FPS = 144;
int frameTime = 0;
SDL_Window *window = nullptr;
SDL_Texture *currentImage= nullptr;
SDL_Renderer *renderTarget = nullptr;
SDL_Rect playerRect;
int frameWidth, frameHeight;
int textureWidth, textureHeight;
SDL_Init(SDL_INIT_VIDEO );
int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG;
if (!(IMG_Init(imgFlags) != imgFlags))
{
std::cout << "Error: " << IMG_GetError() << std::endl;
}
window = SDL_CreateWindow("SDL Pong", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1024, 720, SDL_WINDOW_SHOWN);
renderTarget = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
currentImage = LoadTexture("Untitled.jpg", renderTarget);
SDL_QueryTexture(currentImage, NULL, NULL, &textureWidth, &textureHeight);
SDL_SetRenderDrawColor(renderTarget, 0xFF, 0, 0, 0xFF);
frameWidth = textureWidth / 3;
frameHeight = textureHeight / 4;
playerRect.x = playerRect.y = 0;
playerRect.y = frameWidth;
playerRect.h = frameHeight;
bool isRunning = true; //game loop
SDL_Event ev;
while (isRunning)
{
while (SDL_PollEvent(&ev) != 0)
{
if (ev.type == SDL_QUIT)
isRunning = false;
}
frameTime++;
if (FPS / frameTime == 4)
{
frameTime = 0;
playerRect.x += frameWidth;
if (playerRect.x >= textureWidth)
playerRect.x =0;
}
SDL_RenderClear(renderTarget);
SDL_RenderCopy(renderTarget, currentImage, &playerRect, NULL);
SDL_RenderPresent(renderTarget);
}
SDL_DestroyWindow(window);
SDL_DestroyTexture(currentImage);
SDL_DestroyRenderer(renderTarget);
window = nullptr;
renderTarget = nullptr;
currentImage = nullptr;
SDL_Quit();
return 0;
}
This is the error message: http://imgur.com/LHMdt5F
IMG_Init returns bitfield of formats that was initialised. If resulting bitfield doesn't contain every format that was requested in flags, something gone wrong.
if (!(IMG_Init(imgFlags) != imgFlags)) checks if there is no error. Then you're trying to get error message, but there were no errors. Remove negation operator.
When you create the .exe and run it from an IDE it often stores the executable in a ../bin/.. directory. If Untitled.jpg is in the same directory as your source files, it will not find it.
SDL_GetBasePath(); will return the base path to your files. Check it out docs for it.
The string from SDL_GetBasePath() + "Untitled.jpg" will find and open the file.

SDL2 Access violation multiple windows

I am developing SDL2 application which needs to have multiple windows on multiple monitors. And I am getting access violation when drawing string with SDL_ttf library. I should also mention that Application is opening windows in separate threads and is working ok if there is no SDL_ttf used.
I get this for exception when using SDL_ttf:
Unhandled exception at 0x0F2BC191 (SDL2.dll) in SDLMultipleWindows.exe: 0xC0000005: Access violation writing location 0x0100000C.
And access violation is happening in this function:
bool loadFromRenderedText( std::string textureText, SDL_Color textColor )
{
SDL_Surface* textSurface = TTF_RenderText_Solid( gFont, textureText.c_str(), textColor );
SDL_Texture * mTexture = NULL;
int w, h;
if( textSurface != NULL )
{
mTexture = SDL_CreateTextureFromSurface( renderer, textSurface );
w = textSurface->w;
h = textSurface->h;
SDL_FreeSurface( textSurface );
}
else
{
printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
}
SDL_Rect renderQuad = { 250, 300, w, h };
int result = SDL_RenderCopyEx( renderer, mTexture, NULL, &renderQuad, 0.0, NULL, SDL_FLIP_NONE );
OutputDebugString(SDL_GetError());
return true;
}
Exception happens on SDL_CreateTextureFromSurface(renderer, textSurface);
This is stack trace from Visual studio:
SDL2.dll!SDL_malloc_REAL(unsigned int bytes) Line 4206 C
SDL2.dll!SDL_calloc_REAL(unsigned int n_elements, unsigned int elem_size) Line 4406 C
SDL2.dll!SDL_CreateRGBSurface_REAL(unsigned int flags, int width, int height, int depth, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int Amask) Line 53 C
SDL2.dll!SDL_ConvertSurface_REAL(SDL_Surface * surface, const SDL_PixelFormat * format, unsigned int flags) Line 840 C
SDL2.dll!SDL_CreateTextureFromSurface_REAL(SDL_Renderer * renderer, SDL_Surface * surface) Line 536 C
SDL2.dll!SDL_CreateTextureFromSurface(SDL_Renderer * a, SDL_Surface * b) Line 342 C
SDLMultipleWindows.exe! loadFromRenderedText(std::basic_string<char,std::char_traits<char>,std::allocator<char> > textureText, SDL_Color textColor) Line 162 C++
Am I doing something wrong or SDL_ttf or SDL2 cannot work on multiple threads?
Is there another way to draw string in SDL2?
Thanks!
Edit:
Adding part of existing code:
ClientWindows::ClientWindows(void)
{
SDL_Init(SDL_INIT_EVERYTHING);
IMG_Init(IMG_INIT_PNG);
TTF_Init();
}
Tread function:
void ClientWindows::WindowThread(int i)
{
AppWindow* rWindow = new AppWindow(i * 1024, 0);
Windows.push_back(rWindow);
rWindow->InitScreen();
}
Start graphics function:
void ClientWindows::StartGraphics(int number)
{
for(int i= 0; i<number; i++)
{
std::thread* wTread = new std::thread(&ClientWindows::WindowThread,this , i);
Threads.push_back(wTread);
}
.
.
.
Client window Constructor:
AppWindow::AppWindow(int x, int y)
{
quit = false;
SCREEN_WIDTH = 1024;
SCREEN_HEIGHT = 768;
imagePositionX = 50;
imagePositionY = 50;
speed_x = 10;
speed_y = 10;
moveX = 10;
moveY = 10;
std::ostringstream convert;
convert << "Graphics";
convert << x;
string name = convert.str();
window = SDL_CreateWindow(name.c_str(), x,
y, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_OPENGL);
if (window == nullptr){
std::cout << SDL_GetError() << std::endl;
}
opengl3_context = SDL_GL_CreateContext(window);
SDL_assert(opengl3_context);
mt.lock();
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer == nullptr){
std::cout << SDL_GetError() << std::endl;
}
mt.unlock();
background = nullptr,image = nullptr;
background = SDLLoadImage("../res/Image1024x768.png");
image = SDLLoadImage("../res/Image1024Classic.png");
animeImage = SDLLoadImage("../res/32_80x80.png");
gFont = TTF_OpenFont("../res/sample.ttf", 28);
}
Client window startGraphics function:
void AppWindow::InitScreen(void)
{
Clear();
Render();
Present();
//Init fps
countedFrames = 0;
fpsTimer.start();
//For tracking if we want to quit
Uint32 frameRate = 0;
while (!quit)
{
if (fpsTimer.getTicks() > frameRate + 15)
{
frameRate = fpsTimer.getTicks();
Clear();
Render();
Present();
}
SDL_Delay(5);
}
}
Function in question:
bool AppWindow::loadFromRenderedText(std::string textureText, SDL_Color textColor)
{
SDL_Surface* textSurface = TTF_RenderText_Solid( gFont, textureText.c_str(), textColor );
SDL_Texture * mTexture = NULL;
int w, h;
if( textSurface != NULL )
{
mTexture = SDL_CreateTextureFromSurface( renderer, textSurface );
w = textSurface->w;
h = textSurface->h;
SDL_FreeSurface( textSurface );
}
else
{
printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
}
SDL_Rect renderQuad = { 250, 300, w, h };
int result = SDL_RenderCopyEx( renderer, mTexture, NULL, &renderQuad, 0.0, NULL, SDL_FLIP_NONE );
OutputDebugString(SDL_GetError());
return true;
}
You can't use SDL2 functions from other threads than the one in which the rendering context was created, SDL2 guarantees no thread safety for drawing functions.
If I recall correctly, the only thread safe part of SDL2 is pushing custom events to the event queue.
So I'm guessing the AccessViolation occurs because you're trying to use the renderering context from another thread than from on the one which it was created on.