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.