I'm calling SDL_RenderCopy and it gets called and returns normally but doesn't draw anything to the window. Edited to make the question and code clearer. I'm thinking I might be trying to use something beyond its scope and hence it can't be called but this doesn't produce any error so I'm not sure. Here's the simple picture I refer to https://commons.wikimedia.org/wiki/Category:PNG_chess_pieces/Standard_transparent#/media/File:Chess_kdt60.png
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
// Recreation of the problem. Doesnt draw anything onto the white screen.
class King{
public:
King(SDL_Renderer *renderer){
SDL_Surface *Piece;
Piece = IMG_Load("Pieces/BK.png"); // I'll attach the picture
king = SDL_CreateTextureFromSurface(renderer, Piece);
SDL_FreeSurface(Piece);
kingRect.h = 100;
kingRect.w = 100;
}
~King(){}
void render(SDL_Renderer *renderer){
SDL_RenderCopy(renderer, king, NULL, &kingRect); // 99% sure the problem is this
}
private:
SDL_Texture *king;
SDL_Rect kingRect;
};
class Game {
public:
Game(const char *title, int sidelength){
isRunning = true;
if(SDL_Init(SDL_INIT_EVERYTHING) != 0) isRunning = false;
window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, sidelength, sidelength, SDL_WINDOW_OPENGL);
if(window == NULL) isRunning = false;
renderer = SDL_CreateRenderer(window, -1, 0);
if(!renderer) isRunning = false;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
}
~Game(){}
void handleEvents(){
//Handles Events. I know this works.
}
}
void update(){};
void render(){
SDL_RenderClear(renderer);
BK.render(renderer);
SDL_RenderPresent(renderer);
}
void clean(){
//Cleans up after. I know this works.
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
}
bool running(){return(isRunning);}
King BK{renderer};
private:
bool isRunning{true};
SDL_Window *window;
SDL_Renderer *renderer;
};
Game *game = nullptr;
int main(int argc, const char *argv[]){
game = new Game("Testing Window", 800);
while(game->running()){
game->handleEvents();
game->update();
game->render();
}
game->clean();
return(0);
}
King BK{renderer}; field gets initialised before your Game::Game finishes and gets a chance to assign a renderer, so it gets NULL instead. NULL is not a valid renderer and can't create textures. If you would have checked for error you would have got Invalid renderer message. Also decent compiler with enabled warnings will tell something like warning: 'Game::renderer' is used uninitialized in this function [-Wuninitialized]; consider enabling better warning levels in your compiler.
Second thing is that you never called IMG_Init with required image formats you intend to load.
Third thing is that code is misformatted and wouldn't compile without modifications. I suggest testing code that you post as MCCVE for still being compilable and reproducing your problem (as MCCVE implies).
Related
I'm doing Lazy Foo's tutorial on SDL (I'm using SDL2-2.0.9), and at the texture rendering part I encountered the following problem: the program compiles and runs as expected, no issue here, but when I close the window, the console doesn't close and the process continues running, so I have to close the console separately.
When I tried to debug it, I found out that the program indeed leaves the main cycle and reaches the "return 0" line in the main function successfully, but then it just hangs like that until I close the console.
The issue is only present when I use the SDL renderer with any option other than SDL_RENDERER_SOFTWARE. If I use SDL_RENDERER_SOFTWARE - the program closes as expected. With other options it stays at "return 0" running other threads (crypt32.dll, ntdll.dll and nvd3dum, in this order in the thread view, meaning that the process is stuck in crypt32).
I'm aware that my main function is not the "real main" as it has been hijacked by SDL, so exit(0) works fine as an ad-hoc solution. But I want to know, why exactly does that happen and is there any other way to fix this, so that I don't have to use exit(0) ?
Here is an example (simplified) code, which demonstrates this issue for me:
#include "SDL.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
SDL_Window *win = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *bitmapTex = NULL;
SDL_Surface *bitmapSurface = NULL;
int width = 640, height = 480;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("Could not initialize SDL");
return 1;
}
win = SDL_CreateWindow("Hello World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0);
renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
bitmapSurface = SDL_LoadBMP("res/x.bmp");
bitmapTex = SDL_CreateTextureFromSurface(renderer, bitmapSurface);
SDL_FreeSurface(bitmapSurface);
bool quit = false;
while (!quit) {
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = true;
}
}
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, bitmapTex, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(bitmapTex);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
printf("REACHED RETURN 0");
return 0;
}
Works as intended, but after closing the window I see "REACHED RETURN 0" printed in console and that's it, the console stays there. The code can be simplified further, the issue will be present as long as there is an instance of SDL_Renderer created.
UPD: The callstack during the hanging:
> ntdll.dll!_NtWaitForMultipleObjects#20()
KernelBase.dll!_WaitForMultipleObjectsEx#20()
crypt32.dll!ILS_WaitForThreadProc()
kernel32.dll!#BaseThreadInitThunk#12()
ntdll.dll!__RtlUserThreadStart()
ntdll.dll!__RtlUserThreadStart#8()
UPD2: The problem is not with the loop at all, I created the simplest application where I just create a window and a renderer and then return 0, it still gives me a hanging console. Like this:
#include <SDL.h>
int main(int argc, char* args[])
{
if (SDL_Init(SDL_INIT_VIDEO) < 0) return 1;
SDL_Window* window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
return 0;
}
Same thing when I destroy them properly. The problem is in the renderer.
UPD3: Here is the Parallel Stack window during the "hanging". There is no "main" thread since I close it successfully, these are the threads which stop the program from closing properly. Other than that, it doesn't give me any understanding of the problem.
i am currently reentering programming in C++ to write a small game. I am using Visual Studio 2017 and SDL2. I am following a series of tutorials to get into SDL. My problem seems to be related to me not entirely understanding the workings of pointers in c++. I am passing a pointer to a function as an argument and want to use it within this function as an argument to another function which returns a pointer to a SDL_Surface. Following my code:
init SDL:
SDL_Surface* init(SDL_Window *window)
{
SDL_Surface *screenSurface = nullptr;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("%s", "Error in init");
}
else
{
screenSurface = SDL_GetWindowSurface(window);
}
return screenSurface;
}
load bmp:
SDL_Surface* loadMedia(const char file[])
{
SDL_Surface *image = SDL_LoadBMP(file);
if (image == nullptr)
{
printf("%s", "Error in loadMedia");
}
return image;
}
main:
int main(int argc, char *argv[])
{
SDL_Window *window = SDL_CreateWindow("xyz", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
SDL_Surface *screenSurface = init(window);
if (screenSurface == nullptr)
{
printf("%s", "surface is null");
}
SDL_Surface *image = loadMedia("resources/images/village.bmp");
SDL_BlitSurface(image, NULL, screenSurface, NULL);
SDL_UpdateWindowSurface(window);
SDL_Delay(1000);
SDL_FreeSurface(image);
image = nullptr;
SDL_DestroyWindow(window);
window = nullptr;
SDL_Quit();
return 0;
}
if i create
SDL_Window *window = SDL_CreateWindow("xyz",...)
as a global variable and initialize it within init(), everything works fine and screenSurface is initialized with a valid value. As soon as i do as it is in the code, pass the pointer window to init() to create the surface there and then return screenSurface, screenSurface = SDL_GetWindowSurface(window) returns null.
I have been programming mostly SAS and Java the last years and didnt touch c++ for several years, so im sure its just a minor misunderstanding on my side but i cannot figure out what it is.
Thx in advance :)
The problem with my code is that I am making a pong game in SDL 2.0 in c++. I did everything until creating the movement. When the player paddle moves, it leaves behind a trail in the same color as the paddle. I watched some videos on YouTube, but when they do the movement it's nice and clear and for me to fix this but I need to recolor the background every time the player moves, which makes it being all flashy and if I hold the button I don't see the paddle at all.
#include<iostream>
#include<SDL2/SDL.h>
#include<SDL2/SDL_image.h>
#include<windows.h>
#define width 800
#define height 600
using namespace std;
bool run = true;
class Player{
private:
SDL_Window* window = SDL_CreateWindow("Pong!", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_RESIZABLE);
SDL_Surface* Screen = SDL_GetWindowSurface(window);
Uint32 screen_color = SDL_MapRGB(Screen->format, 0, 0, 0);
Uint32 In_game_RGB = SDL_MapRGB(Screen->format, 255, 255, 255);
SDL_Rect Pl;
SDL_Rect AI;
SDL_Rect Ball;
SDL_Rect ClearP;
SDL_Rect ClearAI;
public:
Player(){
//Player parameters
Pl.x = 60;Pl.y = 225;Pl.w = 25;Pl.h = 200;
//AI parameters
AI.x = 720;AI.y = 225;AI.w = 25;AI.h = 200;
//Ball parameters
Ball.x = width/2;Ball.y = height/2+10;Ball.w = 25;Ball.h = 25;
//Recoloring parameters
ClearP.x = 0;ClearP.y = 0; ClearP.w = 375;ClearP.h = height;
ClearAI.x = 425;ClearAI.y = 0;ClearAI.w = 375;ClearAI.h = height;
//Make the screen color black
SDL_FillRect(Screen, NULL, screen_color);
}
void scrUpdate(){
SDL_UpdateWindowSurface(window);
}
void drawPlayer(){
SDL_FillRect(Screen, &Pl, In_game_RGB);
}
void drawComputer(){
SDL_FillRect(Screen, &AI, In_game_RGB);
}
void ball(){
SDL_FillRect(Screen, &Ball, In_game_RGB);
}
void Movement(){
if(GetAsyncKeyState(VK_DOWN)){
Pl.y += 2;
SDL_FillRect(Screen,&ClearP,screen_color);
}
if(GetAsyncKeyState(VK_UP)){
SDL_FillRect(Screen,&ClearP,screen_color);
Pl.y -= 2;
}
}
};
void EventCheck(){
SDL_Event event;
if(SDL_PollEvent(&event)){
if(event.type == SDL_QUIT){
run = false;
}
}
}
int main( int argc, char *argv[] )
{
SDL_Init(SDL_INIT_EVERYTHING);
Player Play;
//Player Computer();
while(run){
Play.scrUpdate();
Play.drawPlayer();
Play.drawComputer();
Play.ball();
Play.Movement();
EventCheck();
}
SDL_Quit();
return EXIT_SUCCESS;
}
It would help to show some code or an example of what you have been doing, or a link to one of the videos you have been watching:
Youtube tutorial
but I suggest taking a look at:
screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE); and SDL_Flip(screen) as those have to do with screen buffering and drawing.
Another possibilty is that you are running an outdated version of SDL, or an incompatible one with your current system.
To be able to give a more complete and proper answer, I'd highly suggest adding more information about your code, screenshots of results and your version of SDL and operating system.
Also, you said it was flashy when you hold the paddle. I think it must be that you are performing your logic to move the paddle and you redraw the paddle once it's still. If you are redrawing the entire screen constantly, consider double buffering.
So I'm starting SDL2 and ran through a few tutorials and decided that I would try to make a simple game and a clone of Pong seemed like the simplest. But I can't seem to be able to make the right hand side paddle draw on the window. At the moment I'm using SDL_FillRenderRect, one for each paddle but that just seems to make the left hand side one appear and not the right hand side. Here's my current code:
#include <iostream>
#include "Pong.h"
#include "Paddle.h"
//Screen size
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
bool quit = false;//Has user quit?
Paddle paddleLeft;
Paddle paddleRight;
int Pong::setup(){
//Initilize SDL
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("Pong",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN);
if (window == nullptr){
std::cout<<"SDL_CreateWindow error: "<<SDL_GetError()<<std::endl;
SDL_Quit();
return -1;
}
SDL_ShowCursor(0);
renderer = SDL_CreateRenderer(window,
-1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer == nullptr){
std::cout<<"SDL_CreateRenderer error: "<<SDL_GetError()<<std::endl;
SDL_Quit();
return -1;
}
int wH, wW;
//Setting the paddle to the centre of the left hand side of the screen.
SDL_GetWindowSize(window, &wW, &wH);
paddleLeft.setY((wH / 2) - (paddleLeft.getPaddleHeight() / 2));
paddleRight.setY((wH / 2) - (paddleLeft.getPaddleHeight() / 2));
//Setting the x, y, height and width of the left paddle
leftR.x = 20;
leftR.y = paddleLeft.getY();
leftR.h = paddleLeft.getPaddleWidth();
leftR.w = paddleLeft.getPaddleHeight();
//Setting the x, y, height and width of the right paddle
rightR.x = 620;
rightR.y = paddleLeft.getY();
rightR.h = paddleLeft.getPaddleWidth();
rightR.w = paddleLeft.getPaddleHeight();
return 1;//If setup fails then return -1 otherwise return 1
}
void Pong::updateGame(){
SDL_Event event;
while (SDL_PollEvent(&event)){
if (event.type == SDL_QUIT){
quit = true;
}
if (event.type == SDL_KEYDOWN){
switch (event.key.keysym.sym){
case SDLK_w: paddleLeft.setY(paddleLeft.getY() - paddleLeft.getSpeed()); break;
case SDLK_s: paddleLeft.setY(paddleLeft.getY() + paddleLeft.getSpeed()); break;
}
}
}
}
void Pong::render(){
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
leftR.x = paddleLeft.getX();
leftR.y = paddleLeft.getY();
rightR.x = paddleRight.getX();
rightR.y = paddleRight.getY();
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderFillRect(renderer, &leftR);
SDL_RenderFillRect(renderer, &rightR);
SDL_RenderPresent(renderer);
}
void Pong::cleanup(){
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
void Pong::run(){
while (!quit){
updateGame();
render();
}
cleanup();
}
Could someone please point me in the correct direction for drawing the right paddle? I would also appreciate it if there are anyother errors in my code or ways to make it more efficent and what not if that could also be pointed out. Thanks in advance.
Read this closely:
rightR.x = 620;
rightR.y = paddleLeft.getY();
rightR.h = paddleLeft.getPaddleWidth();
rightR.w = paddleLeft.getPaddleHeight();
right and left mixed up due to copy-paste programming. I'm not saying it's bad, I do it too to reduce harm on my hands. You should just check things like this twice.
Also, in your case, you should start using OOP concepts. Don't perform everything in non-member functions, make member functions that perform on instances instead. I don't know where the values of getY, getPaddleWidth and getPaddleHeight come from, but it's clear to me that there shouldn't be anything other than SDL_Rect holding them.
I even think that SDL is a waste of time and I can't remember what's C++ about it. It's pure C and you're not going to learn anything useful. SFML is far better choice.
I am trying to create a SDL window which keeps its aspect ratio when resize event happens. If user widens the window, the height is increased and vice versa. I catch the SDL_WINDOWEVENT_RESIZED event, calculate new width or height which maintains the aspect ratio and then call SDL_SetWindowSize() with calculated values.
The problem is that calling the SDL_SetWindowSize() function inside the event polling loop does nothing on the screen. SDL does update the window size variables (calling SDL_GetWindowSize() in my main loop returns the updated window dimensions). However, the actual window is not updated.
The only way I can get this to work is to call constantly SDL_SetWindowSize() in the main loop, but I think that is the wrong way of doing things. The code below illustrates my problem. Is there a better and cleaner way to get this to work?
I am using SDL 2.0.3 and 64-bit Ubuntu Linux with GNOME desktop.
#include <SDL2/SDL.h>
static const float ASPECT_RATIO = 16.f/9.f;
SDL_Window* window;
SDL_Renderer* renderer;
uint32_t windowID;
SDL_Rect screen;
bool done = false;
bool resizeDone = false;
void handle_events()
{
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_WINDOWEVENT:
if(e.window.windowID == windowID) {
switch(e.window.event) {
case SDL_WINDOWEVENT_RESIZED: {
int width = e.window.data1;
int height = e.window.data2;
float aspectRatio = (float)width/(float)height;
if(aspectRatio != ASPECT_RATIO) {
if(aspectRatio > ASPECT_RATIO) {
height = (1.f / ASPECT_RATIO) * width;
}
else {
width = ASPECT_RATIO * height;
}
printf("Setting window size to %d, %d, aspect ratio: %f\n",
width, height, (float)width/(float)height);
}
screen.w = width;
screen.h = height;
SDL_SetWindowSize(window, width, height); // <-- does not work
resizeDone = true;
break;
}
}
}
break;
case SDL_QUIT:
done = true;
break;
default:
break;
}
}
}
void run() {
while(!done) {
//SDL_SetWindowSize(window, screen.w, screen.h); // <-- works
handle_events();
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
if(resizeDone) {
int w, h;
SDL_GetWindowSize(window, &w, &h);
printf("SDL_GetWindowSize: %d, %d\n", w, h);
resizeDone = false;
}
}
}
int main(int, char**) {
SDL_Init(SDL_INIT_VIDEO);
uint32_t window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
windowID = SDL_GetWindowID(window);
renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
run();
SDL_Quit();
return 0;
}
Some window managers seems to ignore resize requests made while WM itself resizes window (e.g. while mouse button held). On contrary, SDL_GetWindowSize returns cached values, which in that specific case sometimes happens to be wrong.
I see no platform-independent way to achieve that, other than constantly calling SDL_SetWindowSize on each frame, just in case. It could be achieved using platform-specific APIs, though (like SDL_GetWindowSysWMInfo and then using Xlib).
On macOS, I have solved it like this:
cocoa.m:
#import <Cocoa/Cocoa.h>
void SetWindowRatio(void *window) {
NSWindow *win = (__bridge NSWindow*) window;
win.aspectRatio = NSMakeSize( 1280, 720 );
}
main.cpp:
#include <SDL.h>
#include <SDL_syswm.h>
extern "C" void SetWindowRatio(void *window);
// and later..
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(sdl.window, &wmInfo);
SetWindowRatio(wmInfo.info.cocoa.window);
Perhaps something similar could be done on Linux, only access different part of wmInfo.info. and call the native function?