Taking address of temporary SDL_Rect - c++

I am trying to make a simpler container for text in SDL by way of classes. The class is supposed to contain a pointer to an SDL_Texture and an SDL_Rect as well as some methods to get the information from the instances of the class. My problem arises when I try to blit the texture to the screen with the following function:
//Assume that renderer is already created
SDL_RenderCopy(renderer, texture.getTexture(), NULL, &texture.getRect());
The compiler brings my attention to the fourth parameter and states the following:
error: taking address of temporary [-fpermissive]
The code for my class is:
//Class
class Texture
{
private:
SDL_Texture* texture;
SDL_Rect rect;
public:
Texture(){/*Don't call any of the functions when initialized like this*/}
Texture(SDL_Texture* texure)
{
this->texture = texture;
}
SDL_Texture* getTexture()
{
return texture;
}
SDL_Rect getRect()
{
return rect;
}
void setRect(int posX, int posY, int scale, SDL_Texture* texture)
{
int textW = 0;
int textH = 0;
SDL_QueryTexture(texture, NULL, NULL, &textW, &textH);
this->rect = {posX,posY,textW*scale, textH*scale};
}
};
The code for my main program is:
//Main Program
TTF_Font* font = TTF_OpenFont("./PKMNRSEU.FON", 17);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
Texture texture(renderText(font, "Hello", white, renderer));
texture.setRect(100, 100, 5, texture.getTexture());
bool running = true;
Uint32 startingTick;
SDL_Event event;
while (running)
{
startingTick = SDL_GetTicks();
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
running = false;
break;
}
}
SDL_RenderCopy(renderer, texture.getTexture(), NULL, &texture.getRect());
SDL_RenderPresent(renderer);
clockTick(startingTick);
}
SDL_DestroyRenderer(renderer);
TTF_CloseFont(font);
I have also tried instantiating my object like this:
Texture* texture = new Texture(renderText(font, "Hello", white, renderer));
But I still get the same error. I suspect it is to do with the SDL_Rect not being a pointer.
Thanks in advance!

A simple solution could be to change the signature/implementation of getRect as follows:
SDL_Rect *getRect()
{
return ▭
}
Then you can call SDL_RenderCopy like this:
SDL_RenderCopy(renderer, texture.getTexture(), NULL, texture.getRect());

Related

Showing a video using two textures SDL2

I need to build an interface where on the left side of the screen shows part of one streaming video and the right side the other part. Something like this https://www.youtube.com/watch?v=fSPXpdVzamo
The video streaming is saved on a memory buffer that is being loaded on a texture. My question is how to render just the half of the texture, I've bee trying using SDL_Rect but nothing happens.
This is the relevant part of my code:
SDL_UpdateTexture(texture, NULL, buffer_start, fmt.fmt.pix.width * 2);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
If I try something like this, it doesn't work:
SDL_UpdateTexture(texture, NULL, buffer_start, fmt.fmt.pix.width * 2);
SDL_Rect someRect;
someRect.x = 0;
someRect.y = 0;
someRect.w = 1500;
someRect.h = 3000;
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, &someRect);
SDL_RenderPresent(renderer);
Any advice would be great!
Without you posting a MCVE is hard to know where you went wrong. My guess is your x position is wrong. Here is an example where I show how to draw 2 images in the fashion of your video.
Green image: https://i.imgur.com/yaOG8Ng.png
Red image: https://i.imgur.com/faKKShU.png
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#define HEIGHT 600
#define WIDTH 800
using namespace std;
int main() {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("Red Green", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
bool quit = false;
SDL_Event event;
SDL_Texture *green_part = IMG_LoadTexture(renderer, "Green400x600.png");
SDL_Texture *red_part = IMG_LoadTexture(renderer, "Red400x600.png");
while (!quit) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
quit = true;
}
}
SDL_RenderClear(renderer);
SDL_Rect copy_rect{0, 0, 400, 600};
SDL_RenderCopy(renderer, green_part, nullptr, &copy_rect);
// We now draw from half the screen onward x position = WIDTH / 2.
copy_rect.x = 400;
SDL_RenderCopy(renderer, red_part, nullptr, &copy_rect);
SDL_RenderPresent(renderer);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}

Drawing circles with SDL2?

is there a sdl "draw circle" function? or should i make it from cero?
or, instead of that... is there an already made function in c++ for that?
something like:
int main (){
// create the window
SDL_Window * window1 =
SDL_CreateWindow("Window",700,50,500,450, SDL_WINDOW_SHOWN);
// create the renderer
SDL_Renderer * renderer = SDL_CreateRenderer( window1, -1 , SDL_RENDERER_ACCELERATED);
// Set background
SDL_SetRenderDrawColor( renderer, 255, 255, 255, 255 );
SDL_RenderClear( renderer );
SDL_RenderPresent(renderer);
// Set circle's position
int x = 100; int y = 100;
int radius = 40;
// Loop to hold the window in screen
bool running = true;
while(running) {
SDL_Event event1;
while(SDL_PollEvent(&event1) !=0){
// CIRCLE FUNCTION ??????
functionSDLcircle(x, y, radius);
if(event1.type ==SDL_KEYDOWN) {
switch (event1.key.keysym.sym){
case SDLK_RETURN:
running = false;
break;
}
}
}
}
return 0;
}
Nope, nothing like that off-the-shelf in the SDL_Renderer system.
You'll have to roll your own using SDL_RenderDrawLines()/OpenGL or switch to something like SDL2_gfx.

SDL_Texture causes everything to render black

I have been working on a fairly large app in SDL for a while and recently noticed a strange bug; whenever a window is closed, everything on another window will render completely black. When I draw red a line, it will be black, and when I draw an SDL_Texture, it will draw a black rectangle in place of the image.
After a while, I managed to recreate the problem by making a simplified version of the app from the ground up. The program includes a window class that stores a window, its renderer, and an SDL_Texture. The window class also includes a render function to render things on to its window including the SDL_Texture. There is also a function that allows each window object to handle SDL events such as the window being closed. When the window is closed, the window, renderer, and texture are all destroyed.
class Window {
SDL_Window *window;
SDL_Renderer *renderer;
Uint32 windowID;
SDL_Texture *texture;
void cleanup() {
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_DestroyTexture(texture);
}
bool running = true;
public:
void init() {
window = SDL_CreateWindow("Window", 50, 50, 721, 558, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
windowID = SDL_GetWindowID(window);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
// load texture
SDL_Surface* loadedSurface = IMG_Load("picture.png");
texture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
SDL_FreeSurface(loadedSurface);
}
bool isRunning() {
return running;
}
void render() {
// clear the screen with a green color
SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF);
SDL_RenderClear(renderer);
// create a rectangle for drawing things
SDL_Rect rect = {0, 0, 100, 100};
// draw a red rectangle
SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF);
SDL_RenderFillRect(renderer, &rect);
// draw the texture/image on top of the rectangle
if (SDL_RenderCopy(renderer, texture, NULL, &rect) < 0) {
printf("Unable to render texture! Error: %s\n", SDL_GetError());
}
SDL_RenderPresent(renderer);
}
void events(SDL_Event &e) {
if (e.window.windowID == windowID && e.window.event == SDL_WINDOWEVENT_CLOSE) {
running = false;
cleanup();
}
}
};
The main function manages multiple windows at a time, and separately feeds each one of them SDL events:
int main(int argc, const char * argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) { // initialize SDL and IMG
printf("SDL could not initialize! Error: %s\n", SDL_GetError());
} else if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) {
printf("SDL_image could not initialize! Error: %s\n", IMG_GetError());
} else {
std::vector<Window*> windows; // vector of window objects
// add window objects to the vector
windows.push_back(new Window());
windows.push_back(new Window());
windows.push_back(new Window());
windows.push_back(new Window());
// initialize all windows
for (int i = 0; i < windows.size(); i++) {
windows[i]->init();
}
// game loop
bool loop = true;
while (loop) {
SDL_Delay(50); // delay between each frame
// render all windows
for (int i = 0; i < windows.size(); i++) {
windows[i]->render();
}
// handle new events
SDL_Event e;
while (SDL_PollEvent(&e)) {
// loop backward through windows
// in case one of them has to be
// removed from the vector
for (unsigned long i = windows.size(); i-- > 0;) {
if (windows[i]->isRunning()) {
windows[i]->events(e);
} else {
// delete a window if it has been closed
delete windows[i];
windows.erase(windows.begin() + i);
}
}
}
if (windows.empty()) { // if all windows are closed,
loop = false; // stop the loop
}
}
}
return 0;
}
Now that I have shown my code, I will explain the issue in more detail. When the program starts, four window objects are created, and the windows each show up on the screen. Each of the windows render properly, with a PNG image overlaid on top of a red rectangle. The fourth window, or the last one to be initialized, will only render things such as images, rectangles, and lines in the color black after any other window is closed. The only thing that will render in a different color is SDL_RenderClear, which I used in the above code to render a green background, which exposes the black image and rectangle shapes.
I have tested to make sure the texture, renderer, and window are still valid after this problem occurs, and got no errors.
I would at least like to find what is causing the problem and if there is any possible solution.
You should not destroy window while renderer is still alive. Try executing methods inside of cleanup() in opposite order.
void cleanup()
{
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
}

SDL_Renderer won't show textures after passing through the function

I have a little problem with SDL_Renderer. I can't understand why it doesn't work. Let's look at this example, it works fine:
bool running = true;
SDL_Window* window = SDL_CreateWindow("ASDF", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Texture* texture = IMG_LoadTexture(renderer, "asdf.bmp");
SDL_Event event;
while(running)
{
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_ESCAPE)
{
running = false;
}
break;
default:
break;
}
}
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(texture);
Then it comes to classes and when I pass the renderer through functions, it won't work anymore.
class Sprite
{
public:
Sprite(const std::string& path) : filePath(path) {};
~Sprite() { SDL_DestroyTexture(tex); };
void draw(SDL_Renderer* renderer);
private:
const std::string& filePath;
SDL_Texture* tex;
};
void Sprite::draw(SDL_Renderer* renderer)
{
printf("renderer sprite = %p\n", renderer);
tex = IMG_LoadTexture(renderer, filePath.c_str());
SDL_RenderCopy(renderer, tex, NULL, NULL);
}
int main(int argc, char **argv)
{
bool running = true;
SDL_Window* window = SDL_CreateWindow("ASDF", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Event event;
Sprite* sprite = new Sprite("asdf.bmp");
while(running)
{
printf("renderer main = %p\n", renderer);
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_ESCAPE)
{
running = false;
}
break;
default:
break;
}
}
SDL_RenderClear(renderer);
sprite->draw(renderer);
SDL_RenderPresent(renderer);
}
return 0;
}
The address of renderer is the same in main and in the draw function. I know that I'm probably making some sort of beginner's mistake here but i can't find it out.
The texture is being loaded every frame when you call sprite->draw.
You should move the line tex = IMG_LoadTexture(renderer, filePath.c_str()); to the constructor so that it is only loaded once.
The reason for this is that the texture will not be ready for rendering in the same frame that it is loaded.
As a side note you don't appear to be cleaning up the SDL_Window or SDL_Renderer with their respective destroy functions or calling SDL_Quit although I accept this may have been omitted for submitting the code example.

SDL 2 program uses 1.4 GB of memory?

Okay, so I've been working on this little bouncing DVD logo thingy and I'm running to it slowly taking up more and more memory. Eventually it ends up taking a whopping 1.4 GB then slows down and crashes. Here is the code, what is wrong with it that causes it to do this?
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <SDL2/SDL.h>
#include <SDL2_ttf/SDL_ttf.h>
#include <SDL2_image/SDL_image.h>
// This sets ups the display.
SDL_Window* window = SDL_CreateWindow("DVD Thingy", 100, 100,
800, 600, SDL_WINDOW_SHOWN
| SDL_RENDERER_ACCELERATED
| SDL_RENDERER_PRESENTVSYNC);
SDL_Renderer* screen = SDL_CreateRenderer(window, -1, 0);
void drawText(char text[], int origX, int origY, SDL_Renderer* ren, TTF_Font* font, SDL_Color color) {
SDL_Surface* surfaceMessage = TTF_RenderText_Blended(font, text, color);
SDL_Texture* Message = SDL_CreateTextureFromSurface(ren, surfaceMessage);
int w = surfaceMessage->w;
int h = surfaceMessage->h;
SDL_Rect messageRect = {origX, origY, w, h};
SDL_RenderCopy(ren, Message, NULL, &messageRect);
SDL_DestroyTexture(Message);
}
int main() {
// This initializes the font class.
srand(time(NULL));
TTF_Init();
int skyboxColor = 240;
bool done = false;
int dirX = 1, dirY = 1;
TTF_Font* font = TTF_OpenFont("./Impact.ttf", 18);
TTF_SetFontOutline(font, 1);
int dvdX = rand() % 800, dvdY = rand() % 600-20;
SDL_Color white = {255, 255, 255};
SDL_Event event;
while (!done) {
while (SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_QUIT:
SDL_Quit();
return 0;
default:
break;
}
}
dvdX += dirX;
dvdY += dirY;
if (dvdX > 770) {
dirX = -1;
}
if (dvdX < 0) {
dirX = 1;
}
if (dvdY < -3) {
dirY = 1;
}
if (dvdY > 580) {
dirY = -1;
}
SDL_SetRenderDrawColor( screen, 0, 0, 0, 255);
SDL_RenderClear(screen);
drawText("DVD", dvdX, dvdY, screen, font, white);
SDL_RenderPresent(screen);
SDL_Delay (1/1000 * 60);
}
return 0;
}
It would appear that in the drawText() function you are creating a new SDL_Surface by means of a call to TTF_RenderText_Blended().
You must ensure to free this surface when you are finished with it, which would appear to be at the end of the function it is created in. You already destroy the texture which you create from the surface so all you need to add is one line after that:
SDL_DestroyTexture(Message);
SDL_FreeSurface(surfaceMessage); <- Free the surface
As drawText() was being called constantly in the main while loop, it was bloating memory with SDL_Surfaces.
Just one other point, as you don't seem to be changing the text from "DVD" you could create the texture once and then just draw it where ever you need to. This would be much more efficient than creating, drawing and then destroying every single drame.