I'm writing a function in C++ with the SDL2 library, and I'm stuck with a small problem. The function deals with everything related to the graphics. I want to use it once to create the window, surface and so on ( graphics(0,0) ), and that everytime I use it after that it just updates the value of x and y, and updates the window surface. How can I do it? I've tried everything I could think of, but in order to update the window surface I need to create the window again. Thanks in advance.
void graficos(int var1,int var2){
int x = 0, y = 0; //declare the variables that will determine position of rectangle
x += var1; y += var2; //declare the variables that will modify x & y
//delcare graphics and load them
SDL_Window * window = SDL_CreateWindow("window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
SDL_Surface * surface = SDL_GetWindowSurface(window);
SDL_Surface * texture = SDL_LoadBMP("texture.bmp");
SDL_Rect rectangle = { x, y, 50, 50 };
//render graphics
SDL_BlitSurface(texture, NULL, surface, &rectangle);
//update window
SDL_UpdateWindowSurface(window);
}
First. You can break your function into two: init and graficos like this:
void init( SDL_Window * &window, SDL_Surface * &texture ) {
window = SDL_CreateWindow("window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
0
);
texture = SDL_LoadBMP("texture.bmp");
}
void graficos( SDL_Window * window, SDL_Surface * texture, int var1, int var2 ) {
// You can delete these lines and use var1 and var2 directly
/* int x = 0, y = 0; //declare the variables that will determine position of rectangle
x += var1; y += var2; //declare the variables that will modify x & y
*/
SDL_Surface * surface = SDL_GetWindowSurface(window);
SDL_Rect rectangle = { var1, var2, 50, 50 };
//render graphics
SDL_BlitSurface(texture, NULL, surface, &rectangle);
//update window
SDL_UpdateWindowSurface(window);
}
And here is the usage:
// somewhere in global place
SDL_Window * window;
SDL_Surface * texture;
// somewhere in initialization of programm
init( window, texture ); // call it only ones
...
graficos( window, texture, newX, newY ); // call it every time you need
Second. You can make window and texture as static like this:
void graficos(int var1,int var2){
/* int x = 0, y = 0; //declare the variables that will determine position of rectangle
x += var1; y += var2; //declare the variables that will modify x & y
*/
//delcare graphics and load them
// ---v---
static SDL_Window * window = SDL_CreateWindow("window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
// ---^---
SDL_Surface * surface = SDL_GetWindowSurface(window);
// ---v---
static SDL_Surface * texture = SDL_LoadBMP("texture.bmp");
// ---^---
SDL_Rect rectangle = { x, y, 50, 50 };
//render graphics
SDL_BlitSurface(texture, NULL, surface, &rectangle);
//update window
SDL_UpdateWindowSurface(window);
}
If there will be a voiting, then my voice would be for first :)
Related
I am using SDL2 and SDL_image.h. My current attempt was trying to fit the .PNG image in a SDL_Rect which only hid my image in the rectangle's area and thus did not work. I was following this tutorial to load the .PNG image. I'm looking to make the image stretch to the same size of the screen which is 640x480. This was my attempt:
...
SDL_Rect surfWindRectBC;
SDL_Rect surfWindRectCI;
SDL_Surface * screenSurf = NULL;
SDL_Surface* current = SDL_CreateRGBSurface(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 0, 0, 0);
SDL_Surface * menu = IMG_Load(std::string(".\\sprites\\menu\\background.png").c_str());
...
...
int main() {
surfWindRectBC.w = SCREEN_WIDTH;
surfWindRectBC.h = SCREEN_HEIGHT;
surfWindRectCI.w = 32;
surfWindRectCI.h = 32;
...
...
screenSurf = SDL_GetWindowSurface(window);
current = SDL_ConvertSurface(menu, screenSurf->format,0);
SDL_FreeSurface(menu);
...
...
while (game) {
SDL_Event event;
Uint8 input = 0;
while (SDL_PollEvent(&event)) {...}
SDL_BlitSurface(current, &surfWindRectBC, screenSurf, &surfWindRectCI);
SDL_UpdateWindowSurface(window);
}
...
Looking at documentation maybe you should try using SDL_BlitScaled instead of SDL_BlitSurface
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.
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.
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 .
here is my c++ code:
#include <SDL2/SDL.h>
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
int main( int argc, char* args[] )
{
SDL_Init( SDL_INIT_VIDEO );
gWindow = SDL_CreateWindow( "test", 0,0,640,480, SDL_WINDOW_SHOWN );
gRenderer = SDL_CreateRenderer(gWindow,-1,SDL_RENDERER_ACCELERATED);
SDL_Surface* x = SDL_CreateRGBSurface(0,50,50,32,0xFF,0xFF00,0xFF0000,0XFF000000);
SDL_Surface* y = SDL_CreateRGBSurface(0,640,480,32,0xFF,0xFF00,0xFF0000,0XFF000000);
SDL_Rect a = {0,0,50,50};
SDL_RenderClear(gRenderer);
SDL_FillRect(x,&a,SDL_MapRGBA(x->format,255,255,0,255));
SDL_Rect dest = {0,0,100,100};
SDL_BlitScaled( x, &a, y, &dest ); //Does nothing
dest.x = 200;
SDL_BlitSurface( x, &a, y, &dest );
SDL_Texture* t;
t = SDL_CreateTextureFromSurface(gRenderer,y);
SDL_RenderCopy(gRenderer,t,NULL,NULL);
SDL_RenderPresent(gRenderer);
SDL_Delay(2000);
return 0;
}
well,when you compile this code,you will see there is ONLY ONE rect on the screen.The function SDL_BlitScaled does nothing.
I'm working with Archlinux,gcc 4.8.2,SDL 2.0.1
According to Retired Ninja's answer,I changed my code:
#include <SDL2/SDL.h>
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
int main( int argc, char* args[] )
{
SDL_Init( SDL_INIT_VIDEO );
gWindow = SDL_CreateWindow( "test", 0,0,640,480, SDL_WINDOW_SHOWN );
gRenderer = SDL_CreateRenderer(gWindow,-1,SDL_RENDERER_ACCELERATED);
SDL_Surface* x = SDL_CreateRGBSurface(0,50,50,32,0xFF,0xFF00,0xFF0000,0XFF000000);
SDL_Surface* y = SDL_CreateRGBSurface(0,640,480,32,0xFF,0xFF00,0xFF0000,0XFF000000);
SDL_SetRenderDrawColor(gRenderer,255,255,255,255);
SDL_RenderClear(gRenderer);
SDL_Rect a = {0,0,25,25};
SDL_FillRect(x,&a,SDL_MapRGBA(x->format,255,255,0,255));
a.x = 25;a.y = 25;
SDL_FillRect(x,&a,SDL_MapRGBA(x->format,255,0,0,255));
SDL_FillRect(y,&y->clip_rect,SDL_MapRGBA(y->format,255,0,255,128));
SDL_Rect dest = {0,0,100,100};
SDL_Rect x_rect = {0,0,50,50};
SDL_SetSurfaceBlendMode(x,SDL_BLENDMODE_NONE);
SDL_BlitScaled( x, &x_rect, y, &dest );
SDL_Texture* t;
t = SDL_CreateTextureFromSurface(gRenderer,y);
SDL_RenderCopy(gRenderer,t,NULL,NULL);
SDL_RenderPresent(gRenderer);
SDL_Delay(2000);
return 0;
}
there is another problem appeared.I try to copy x into y,The x covered y entirely,even through there are transparent area in x.But if I don't use SDL_BLENDMODE_NONE,the alpha of the area copied into y will be set into 128,which is not my purpose.
Filling y with a color makes it work.
I added:
SDL_FillRect(y, &y->clip_rect, SDL_MapRGBA(x->format, 255, 0, 0, 255));
after the SDL_FillRect for x and it worked.
Some further experimentation of just filling a portion of y with alpha leads me to believe that SDL_BlitScaled isn't copying the alpha from the source surface so unless the dest surface has alpha where the destination rect is you won't see the result.
Some more experimentation shows that the default blend mode for a surface is SDL_BLENDMODE_BLEND and changing the mode for y to SDL_BLENDMODE_NONE also makes it work.