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.
Related
I am extremely new to game development. I am attempting to move sprites on a window with SDL. I was using http://gamedevgeek.com/tutorials/moving-sprites-with-sdl/ as a reference for this to help me get a feel for SDL. However, this method of blit doesn't work with SDL2. I researched and found that I must convert surfaces to textures and render those, but I am running into some frustrating difficulties. When ran, the background image seems to render fine, but the sprite only appears in the corner of the window, and when moved, it seems to be overwritten by the background. Here is the code:
#include <iostream>
#include "stdafx.h"
#include <SDL.h>
#include <SDL_image.h>
const int WIDTH = 900;
const int HEIGHT = 360;
const int SPRITE_SIZE = 256;
int main(int argc, char *argv[])
{
SDL_Surface *imageSurface = NULL;
SDL_Surface *windowSurface = NULL;
SDL_Surface *temp = NULL;
SDL_Surface *sprite = NULL;
SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface);
SDL_Rect rcSprite;
SDL_Rect gdSprite;
SDL_Event windowEvent;
SDL_Event event;
SDL_Renderer *renderer = NULL;
SDL_Texture *texture;
SDL_Texture *spriteTexture;
const Uint8 *keystate;
int colorkey;
int count;
int xPosition = 0;
int yPosition = 0;
int gameover = 0;
SDL_Window *window = SDL_CreateWindow("ABDUCTO", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_ALLOW_HIGHDPI);
windowSurface = SDL_GetWindowSurface(window);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
imageSurface = IMG_Load("farm.png");
sprite= IMG_Load("sprite6.png");
texture = SDL_CreateTextureFromSurface(renderer, imageSurface);
spriteTexture = SDL_CreateTextureFromSurface(renderer, sprite);
SDL_FreeSurface(sprite);
SDL_FreeSurface(imageSurface);
//rcSprite used as source rectangle, gdSprite as destination rectangle. Initialize them to the same position
rcSprite.x = xPosition;
rcSprite.y = yPosition;
rcSprite.w = SPRITE_SIZE;
rcSprite.h = SPRITE_SIZE;
gdSprite.x = xPosition;
gdSprite.y = yPosition;
gdSprite.w = SPRITE_SIZE;
gdSprite.h = SPRITE_SIZE;
while (!gameover)
{
if (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
gameover = 1;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
case SDLK_q:
gameover = 1;
break;
}
break;
}
}
keystate = SDL_GetKeyboardState(NULL);
// When key pressed, update the destination rectangle
if (keystate[SDL_SCANCODE_LEFT]) {
gdSprite.x -= 2;
}
if (keystate[SDL_SCANCODE_RIGHT]) {
gdSprite.x += 2;
}
if (keystate[SDL_SCANCODE_UP]) {
gdSprite.y -= 2;
}
if (keystate[SDL_SCANCODE_DOWN]) {
gdSprite.y += 2;
}
if (gdSprite.x < 0) {
gdSprite.x = 0;
}
else if (gdSprite.x > WIDTH - SPRITE_SIZE) {
gdSprite.x = WIDTH - SPRITE_SIZE;
}
if(gdSprite.y < 0) {
gdSprite.y = 0;
}
else if (gdSprite.y > HEIGHT - SPRITE_SIZE) {
gdSprite.y = HEIGHT - SPRITE_SIZE;
}
//Render the window
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderCopy(renderer, spriteTexture, &rcSprite, &gdSprite);
SDL_RenderPresent(renderer);
//SDL_BlitSurface(imageSurface, NULL, windowSurface, NULL);
//SDL_BlitSurface(sprite, NULL, imageSurface, &rcSprite);
//SDL_UpdateWindowSurface(window);
//update the source rectangle to move with the sprite??
rcSprite.x = gdSprite.x;
rcSprite.y = gdSprite.y;
}
SDL_DestroyTexture(spriteTexture);
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
return 0;
SDL_Quit();
}
Any input is appreciated. Thank you.
probably has to do something with the path of your images, or copying the files into the resources on compilation.
are you on windows, osx or linux?
What IDE are you using?
But i noticed two things:
1)
Before the SDL_CreateWindow you should initialize SDL:
SDL_Init(SDL_INIT_EVERYTHING);
2)
SDL_Quit(); will never be called because one line above you quit the main function with return 0;
=> you should swap the lines!
noticed some more:
3) DON'T update the source rectangle to move with the sprite
just render the whole sprite to the gdSprite loction:
SDL_RenderCopy(renderer, sTexture, NULL, &gdSprite);
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.
How using SDL_CreateTexture create transparent texture? By default I'm creating texure with such code:
SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,SDL_TEXTUREACCESS_TARGET, x, y);
And then I'm paining on this texture with redirecting output to this texture. However at the end what I want to render this on screen any (nonupdated) pixel is black.
I have tried different ways with using of:
SDL_RenderClear(_Renderer);
or even with drawing and on created texture with painting transparent Rect with different blending modes but all I had as a result was still nontransparent texture :/
SDL_Rect rect={0,0,Width,Height};
SDL_SetRenderDrawBlendMode(_Renderer,SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(_Renderer,255,255,255,0);
SDL_RenderFillRect(_Renderer,&rect);
To be more specific:
//this->texDefault.get()->get() = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,SDL_TEXTUREACCESS_TARGET, x, y);
SDL_SetRenderTarget(_Renderer.get()->get(), this->texDefault.get()->get());
SDL_SetRenderDrawBlendMode(this->_Renderer.get()->get(),SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(this->_Renderer.get()->get(),255,0,255,0);
SDL_RenderClear(this->_Renderer.get()->get());
//SDL_Rect rect={0,0,Width,Height};
//SDL_SetRenderDrawColor(this->_Renderer.get()->get(),255,255,255,255);
//SDL_RenderFillRect(this->_Renderer.get()->get(),&rect);
//SDL_RenderClear(this->_Renderer.get()->get());
//SDL_SetRenderDrawBlendMode(this->_Renderer.get()->get(),SDL_BLENDMODE_NONE);
SDL_SetRenderTarget(_Renderer.get()->get(), NULL);
SDL_Rect rect= {relTop+Top,relLeft+Left,Height,Width};
SDL_SetRenderDrawBlendMode(this->_Renderer.get()->get(),SDL_BLENDMODE_BLEND);
SDL_RenderCopy(this->_Renderer.get()->get(), this->texDefault->get(), NULL, &rect);
This code is always producing nontransparent Texture independenty what i will set for blending and alpha
The result is :
Maybe there is some other simple method to create transparent empty texture in SDL2 something like x/y-sized fully transparent png but loading having such image in file is little bit pointless :/
First, you need to set renderer blend mode: SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);.
Second, you need to set texture blend mode: SDL_SetTextureBlendMode(textures[i], SDL_BLENDMODE_BLEND);.
Here is working example I created. You can use keys A and S to change alpha channel of third texture, which is invisible at start of the application.
#include <iostream>
#include <vector>
#include <SDL.h>
void fillTexture(SDL_Renderer *renderer, SDL_Texture *texture, int r, int g, int b, int a)
{
SDL_SetRenderTarget(renderer, texture);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer, r, g, b, a);
SDL_RenderFillRect(renderer, NULL);
}
void prepareForRendering(SDL_Renderer *renderer)
{
SDL_SetRenderTarget(renderer, NULL);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
}
void checkSdlError()
{
const char *sdlError = SDL_GetError();
if(sdlError && *sdlError)
{
::std::cout << "SDL ERROR: " << sdlError << ::std::endl;
}
}
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_HAPTIC);
SDL_Window *window = SDL_CreateWindow("SDL test",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
320, 240,
SDL_WINDOW_OPENGL);
SDL_Renderer *renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
const int width = 50;
const int height = 50;
::std::vector<SDL_Texture*> textures;
SDL_Texture *redTexture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
textures.push_back(redTexture);
SDL_Texture *greenTexture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
textures.push_back(greenTexture);
SDL_Texture *purpleTexture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
textures.push_back(purpleTexture);
// Here is setting the blend mode for each and every used texture:
for(int i = 0; i < textures.size(); ++i)
{
SDL_SetTextureBlendMode(textures[i], SDL_BLENDMODE_BLEND);
}
int purpleAlpha = 0;
fillTexture(renderer, redTexture, 255, 0, 0, 255);
fillTexture(renderer, greenTexture, 0, 255, 0, 128);
fillTexture(renderer, purpleTexture, 255, 0, 255, purpleAlpha);
prepareForRendering(renderer);
bool running = true;
while(running)
{
SDL_Rect rect;
rect.w = width;
rect.h = height;
SDL_RenderClear(renderer);
rect.x = 50;
rect.y = 50;
SDL_RenderCopy(renderer, redTexture, NULL, &rect);
rect.x = 75;
rect.y = 70;
SDL_RenderCopy(renderer, greenTexture, NULL, &rect);
rect.x = 75;
rect.y = 30;
SDL_RenderCopy(renderer, purpleTexture, NULL, &rect);
SDL_RenderPresent(renderer);
// Process events
{
SDL_Event event;
while(SDL_PollEvent(&event) == 1)
{
if(event.type == SDL_QUIT)
{
running = false;
}
else if(event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_ESCAPE:
running = false;
break;
case SDLK_a:
purpleAlpha = ::std::max(purpleAlpha - 32, 0);
fillTexture(renderer, purpleTexture, 255, 0, 255, purpleAlpha);
prepareForRendering(renderer);
::std::cout << "Alpha: " << purpleAlpha << ::std::endl;
break;
case SDLK_s:
purpleAlpha = ::std::min(purpleAlpha + 32, 255);
fillTexture(renderer, purpleTexture, 255, 0, 255, purpleAlpha);
prepareForRendering(renderer);
::std::cout << "Alpha: " << purpleAlpha << ::std::endl;
break;
}
}
}
checkSdlError();
}
}
for(int i = 0; i < textures.size(); ++i)
{
SDL_DestroyTexture(textures[i]);
}
textures.clear();
SDL_DestroyRenderer(renderer);
renderer = NULL;
SDL_DestroyWindow(window);
window = NULL;
SDL_Quit();
checkSdlError();
return 0;
}
EDIT: Completely rewritten the answer, original one basically contained blend mode of renderer.
I'm a beginner in SDL and I am simply experimenting with movement of sprites in SDL. I have a rectangle at the bottom of the screen that you can move left and right. However, when you move the sprite left and right, it "duplicates", creating a sort of trace/snake-game-like effect when you move the player left and right. Any ideas on how to fix this?
///the headers
#include "stdafx.h"
#include <SDL.h>
#include <SDL_image.h>
#include <string>
using namespace std;
//screen attributes
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 480;
const int SPRITE_SIZE = 32;
//the surfaces
SDL_Surface *image = NULL;
SDL_Surface *screen = NULL;
int main( int argc, char* argv[] )
{
SDL_Surface *screen, *temp,/* *temp2*/ *sprite/*, *sprite2*/;
SDL_Rect rcSprite/*, rcSprite2*/;
SDL_Event event;
Uint8 *keystate;
int gameover;
//initiailise sdl
SDL_Init(SDL_INIT_VIDEO);
SDL_WM_SetCaption("Pong Move Test", "Pong Move Test");
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
//load the sprite (paddle)
temp = SDL_LoadBMP("pongpaddle1.bmp");
sprite = SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);
//set positions of sprite
rcSprite.x = 400;
rcSprite.y = 450;
gameover = 0;
//message pump
while (!gameover)
{
//look for an event
if (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
gameover = 1;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
case SDLK_q:
gameover = 1;
break;
}
break;
}
}
//handle sprite movement
keystate = SDL_GetKeyState(NULL);
if (keystate[SDLK_LEFT])
{
rcSprite.x -= 1;
}
if (keystate[SDLK_RIGHT])
{
rcSprite.x += 1;
}
//colide with edges of screen
if (rcSprite.x < 0)
{
rcSprite.x =0;
}
else if (rcSprite.x > (SCREEN_WIDTH - SPRITE_SIZE))
{
rcSprite.x = (SCREEN_WIDTH - SPRITE_SIZE);
}
//draw the sprite
SDL_BlitSurface(sprite, NULL, screen, &rcSprite);
//update the screen
SDL_UpdateRect(screen, 0, 0, 0, 0);
}
//clean up area
SDL_FreeSurface(sprite);
SDL_Quit();
return 0;
}
You aren't clearing the screen before drawing each frame, so you're actually drawing over the previous frame, which is why you get a 'trailing' effect.
You can solve this by using SDL_FillRect to fill the entire screen with a background color before drawing each frame:
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
I recently started programming with SDL and I've been following some tutorials on gamedevgeek and lazyfoo. I got to show images on the screen, but when I tried to move them I realized the screen was not updating correctly, making the sprite leave a trace, like in this image:
As you can see, the sprite started out in the top left corner, and it left a trace throughout its path to the bottom right.
Some info that can help:
I'm using a raspberry pi with raspbian.
I'm using SDL 1.2.
What have I tried:
I tried changing the last parameter of SDL_SetVideoMode to SDL_HWSURFACE, SDL_SWSURFACE, SDL_DOUBLEBUF, SDL_FULLSCREEN
I tried to switch between SDL_Flip(screen) and SDL_UpdateRect(screen, 0, 0, 0, 0); when I changed the parameter of SDL_SetVideoMode.
Here is my code.
#include "SDL.h"
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
int main ( int argc, char *argv[] )
{
SDL_Surface *screen, *temp, *sprite;
SDL_Rect rcSprite;
SDL_Event event;
Uint8 *keystate;
int colorkey, gameover;
SDL_Init(SDL_INIT_VIDEO);
// screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SDL_DOUBLEBUF | SDL_FULLSCREEN);
// screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SDL_HWSURFACE);
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SDL_SWSURFACE);
temp = SDL_LoadBMP("sprite.bmp");
sprite = SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);
colorkey = SDL_MapRGB(screen->format, 255, 0, 255);
SDL_SetColorKey(sprite, SDL_SRCCOLORKEY | SDL_RLEACCEL, colorkey);
rcSprite.x = 0;
rcSprite.y = 0;
gameover = 0;
while (!gameover)
{
if (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
gameover = 1;
break;
}
break;
}
}
keystate = SDL_GetKeyState(NULL);
if (keystate[SDLK_LEFT] )
rcSprite.x -= 2;
if (keystate[SDLK_RIGHT] )
rcSprite.x += 2;
if (keystate[SDLK_UP] )
rcSprite.y -= 2;
if (keystate[SDLK_DOWN] )
rcSprite.y += 2;
SDL_BlitSurface(sprite, NULL, screen, &rcSprite);
// SDL_Flip(screen);
SDL_UpdateRect(screen, 0, 0, 0, 0);
}
SDL_FreeSurface(sprite);
SDL_FreeSurface(grass);
SDL_Quit();
return 0;
}
What am I doing wrong? Needless to say that I'm very new to the linux world, as well as the raspberry pi's, as well as SDL's :)
You call to SDL_SetVideoMode() is incorrect, your code should not compile, enable your compiler warnings.
The function takes four arguments:
SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags);
so it should be something like:
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32 , SDL_SWSURFACE);
if( !screen )
//print your warning and exit.
Also your screen surface is never cleared and the sprite remains. Either redraw the entire screen with sprites or clear the surface
SDL_FillRect( screen , NULL , 0x0 ) ; //fills the entire surface with 0x0 .