I'm new to game development, SDL and C++. I have been learning with the code here:
http://gamedevgeek.com/tutorials/managing-game-states-in-c/
The relevant bit:
Multiple states are not only important in demos, but also in games in general. Every game starts off in an introduction state, then moves to a menu of some kind, a finally play begins. When you’re finally defeated, the game moves to a game-over state, usually followed by a return to the menu. In most games it is possible to be in more than one state at a time. For example, you can usually bring up the menu during game play.
My question is: To have multiple states display at once, such as displaying a menu on top of game play, must each state have it's own Renderer?
You pass an Image.png*(or other format) onto a Texture, Then you place the Texture on a "surface"(you can clip the texture with this) which is then passed onto a Renderer. So, all you have to do is change the clip and texture, and pass it to the Renderer In the !RIGHT ORDER!
Example: You would Render the background first, and then Sprites, and then Effects, etc...
I hope this helps.
BELOW CODE WAS TAKEN FROM LAZY FOO WEBSITE!! CHECK IT OUT VERY USEFULL TO BEGIN SDL2
http://lazyfoo.net/tutorials/SDL/07_texture_loading_and_rendering/index.php
//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;
}
}
//Clear the last frame
SDL_RenderClear( gRenderer );
//Render texture to screen
SDL_RenderCopy( gRenderer, gTexture1, NULL, NULL );
SDL_RenderCopy( gRenderer, gTexture2, NULL, NULL );
SDL_RenderCopy( gRenderer, gTexture3, NULL, NULL );
SDL_RenderCopy( gRenderer, gTexture4, NULL, NULL );
//Update screen
SDL_RenderPresent( gRenderer );}
as you can see in the above CODE the SDL_RenderCopy uses the SAME renderer for RENDERING different TEXTURES. so what you need, is, many textures.
I'm certain there might be a use for multiple renderers but I have no idea why you would do that?
//the next day//
So I checked this out, and Saw that if you have a Multiple Window Application you Can use Multiple renderers.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 months ago.
Improve this question
I'm starting a new project in SDL2 and as I'm still trying out different architectural approaches I usually start out by bringing up a white window to confirm that the new approach I'm trying out satisfies at least the bare minimum to get started with SDL2.
This time, I wanted to try wrapping my application into a separate Application class so as to unclutter main, like so:
#include <SDL2/SDL.h>
#include <stdio.h>
#include <string>
#include "HApplication/HApplication.h"
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
int main(int argc, char *argv[])
{
HApplication application = HApplication( SCREEN_WIDTH, SCREEN_HEIGHT );
bool hasStarted = application.checkRunning();
if ( hasStarted ){
application.run();
}
else{
std::string msg = "Application failed to initialize.";
SDL_LogError( SDL_LOG_CATEGORY_ERROR, msg.c_str() );
}
// add error codes
return 0;
}
Now, the run method in HApplication is meant to reflect the main loop until the user exits. For test purposes, I'd just like to get two lines crossing in the middle on a white background. After initializing SDL, the window, and the renderer, which all work out fine, I'm presented with a window filled completely back, although I've used very similar code successfully before:
void HApplication::run()
{
// while user doesn't quit, keep going
bool userQuit = false;
SDL_Event e
while( !userQuit )
{
// handle queued events
while ( SDL_PollEvent( &e ) != 0 )
{
if ( e.type == SDL_QUIT )
{
userQuit = true;
}
}
// clear screen
SDL_SetRenderDrawColor( appRenderer, 255, 255, 255, 255);
SDL_RenderClear( appRenderer );
// draw cross
SDL_SetRenderDrawColor( appRenderer, 0, 0, 0, 255 );
SDL_RenderDrawLine( appRenderer, 0, screenHeight/2, screenWidth, screenHeight/2);
SDL_SetRenderDrawColor( appRenderer, 0, 0, 0, 255 );
SDL_RenderDrawLine( appRenderer, screenWidth/2 , 0, screenWidth/2, screenHeight);
// update screen with new scene
SDL_RenderPresent( appRenderer );
SDL_UpdateWindowSurface( appWindow );
}
close();
}
I'm not quite sure why this happens, especially since I can see what I want stepping through the loop step-by-step using the debugger. I am quite honestly pretty much at a loss at where to even start.
I tried looking on Google and Stackoverflow for similar questions. However, these were mostly addressing problems with loading textures, which I haven't even gotten to yet.
If possible, I would like to keep a separate class handling game logic and resources.
EDIT: It seems like I needed to get rid of SDL_UpdateWindow. However, I'm not quite sure why. If anyone has an explanation, I'd be happy to hear!
SDL has both a CPU rendering API and a GPU one.
Everything that works with a SDL_Renderer belongs to the GPU API. For example, you can make a SDL_Texture and use SDL_RenderCopy to render it. The final step is to call SDL_RenderPresent so that everything that was rendered gets displayed.
SDL_UpdateWindowSurface is part of the CPU API. To use this API, you can for example draw to a SDL_Surface and then use SDL_BlitSurface with SDL_GetWindowSurface to render to the window's surface. The final step is to call SDL_UpdateWindowSurface to display the changes, which is the equivalent to SDL_Flip in SDL 1.2.
In short: after the SDL_RenderPresent call, you get what you wanted, but after the SDL_UpdateWindowSurface call, you overwrite that with the CPU window surface which is probably initialized to black. Just remove that SDL_UpdateWindowSurface call and use the GPU API only.
Im working on a project with my friend and we have run into an issue with surfaces and windows in SDL.
Currently we are able to create a window and display a rectangle on that window and move it around. The next thing we want to do is take a image and display it on a rectangle and then move it around the screen.
We started with taking the SDL_window* and turning it into SDL_surface* though this would take the image and display it on the background of the window.
Is there a way to turn a rectangle we create into a surface and display the image on that rectangle?
I have also tried using textures and it distorts the image when I tried to move it and the whole image doesn’t move with the rectangle.
// this happens in the constructor
temp_image_sur = IMG_Load( image_location.c_str() );
if( temp_image_sur == NULL )
{
std::cout << "Image could not be loaded" <<std::endl;
exit(1);
}
// This is in the actual draw function.
display_surface = SDL_GetWindowSurface( display_window );
if(display_surface == NULL )
{
printf(" null im exiting here %s\n", SDL_GetError());
exit(1);
}
image_surface = SDL_ConvertSurface( temp_image_sur, display_surface->format, 0 );
image_size = { this->location.x, this->location.y, this->size.width, this->size.height };
SDL_BlitSurface( image_surface, &image_size, display_surface, &image_size );
This is what we did for our first attempt, and the image was displaying on the base window. I believe I understand why it is displaying on the base window, it is because we are using that window as the surface, though I'm confused how do I make a user defined rectangle the surface?
We did try using SDL_CreateRGBSurface, though nothing is being displayed on the screen when we do this either.
display_surface = SDL_CreateRGBSurface(0, this->size.width, this->size.height, 1, this->color.red, this->color.green, this->color.blue, this->color.alpha);
Thanks guys!
Please let me know if there is anymore information you need, this is my first time posting and I tried to put all the info that I could think of.
Create a texture from your image surface by using SDL_CreateTextureFromSurface:
SDL_Texture* image_surface = SDL_CreateTextureFromSurface(renderer, temp_image_sur);
(remember to free it with SDL_DestroyTexture)
then use SDL_RenderCopy to draw it:
SDL_RenderCopy(renderer, image_texture, nullptr, &image_rect);
where image_rect is a SDL_Rect and the destination rectangle you want to draw your image to, for example:
SDL_rect image_rect = {10, 10, 200, 200};
To move your image simply change image_rect.x and/or image_rect.y
I am currently developing a small game in SDL in CodeBlocks and it seems i got into a little bit of trouble with surface and texture management. My current progress is getting to move a texture on-screen using the arrow keys. However, i have noticed that when loading a relatively large image, FPS drops drastically and thus the texture i move on-screen moves a lot slower.
My draw function looks like this :
const char* assets[5]={"assets/textures/0.tga","assets/textures/1.tga",
"assets/textures/2.tga","assets/textures/3.png","assets/textures/4.png"};
SDL_Surface* tex[5];
void DrawImage(int i, SDL_Surface* &dest, SDL_Rect &rect)
{
if(tex[i]==NULL) tex[i] = IMG_Load(assets[i]);
SDL_BlitSurface(tex[i], NULL, dest, &rect);
}
with the fourth texture in the array being the large one. If i issue any of the following :
DrawImage(0, screenSurface, rect);
DrawImage(1, screenSurface, rect);
DrawImage(2, screenSurface, rect);
DrawImage(4, screenSurface, rect);
everything runs smooth. However, if i issue:
DrawImage(3, screenSurface, rect);
and keep the texture in the window's bounds, everything runs in slow motion. Moving the texture outside the window's bounds makes everything run normal again.
The main loop looks like this :
bool running = true;
while(running)
{
SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0, 0, 0));
DrawImage(3, screenSurface, rect);
MovePlayer(rect, state);
MoveCursor(NULL, NULL, screenSurface);
SDL_PumpEvents();
SDL_UpdateWindowSurface(window);
if (state[SDL_SCANCODE_ESCAPE])
{
SDL_DestroyWindow(window);
running = false;
}
}
Is there any way to overcome this problem?
Thanks in advance.
Look into SDL_Renderer to make use of hardware rendering. SDL_UpdateWindowSurface uses software rendering and can be very slow.
I'm basically a beginner in C++ but was looking into how to update a string that is in a while loop?
Currently every iteration of the loop it writes the text on top of the previous still its basically a blur of white colour.
This is my loop that im testing with:
while(!quit){
while( SDL_PollEvent( &event ) ){
switch(event.type){
case SDL_QUIT: quit = true; break;
case SDL_MOUSEMOTION: handle_mouse_position();
}
}
SDL_Rect offset;
offset.x = 400;
offset.y = 290;
std::stringstream s;
s << "Mouse xpos: " << mouseX << " Mouse ypos: " << mouseY;
font_surface = TTF_RenderText_Solid(font,s.str().c_str(),font_color);
SDL_BlitSurface(font_surface, NULL, screen, &offset);
//Update the screen
if( SDL_Flip( screen ) == -1 ) {
return 1;
}
}
Is there some way to clear the previous text output and update it each loop so that it will display mouse position clearly?
You are not clearing the screen between redraws, so it just paints over the already painted text (or anything), and it becomes "blur of white" as you say.
For example, try fillrect on the screen every frame.
Extra note: it seems you are not freeing the font_surface --> memory leak.
You can do that redrawing everything each time, or if your background is a solid color, paint a rectangle and draw the text above it.
The second one is more efficient. But if you have a complex scenario it is better to work with layers. First you render the bottom layer, then the second, and so on... By layers I mean, you can have a background() which draws the background and foreground() which, obviously, draws the foreground. So what you will have is something like:
while (main_loop) {
background();
foreground();
}
So you can easily handle more complex scenarios.
I wish to have a semi-transparent SDL background (nothing to do with sub-surfaces or images), such that instead of having a black background it is actually transparent, but the other things I draw are not. My current code is a slightly modified copy of Code::Blocks' SDL project, similar to how various applications have rounded borders or odd shapes besides rectangles.
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#ifdef __APPLE__
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
int main ( int argc, char** argv )
{
putenv("SDL_VIDEO_WINDOW_POS");
putenv("SDL_VIDEO_CENTERED=1");
// initialize SDL video
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "Unable to init SDL: %s\n", SDL_GetError() );
return 1;
}
// make sure SDL cleans up before exit
atexit(SDL_Quit);
// create a new window
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 16,
SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_NOFRAME);
if ( !screen )
{
printf("Unable to set 640x480 video: %s\n", SDL_GetError());
return 1;
}
// load an image
SDL_Surface* bmp = SDL_LoadBMP("cb.bmp");
if (!bmp)
{
printf("Unable to load bitmap: %s\n", SDL_GetError());
return 1;
}
// centre the bitmap on screen
SDL_Rect dstrect;
dstrect.x = (screen->w - bmp->w) / 2;
dstrect.y = (screen->h - bmp->h) / 2;
// program main loop
bool done = false;
while (!done)
{
// message processing loop
SDL_Event event;
while (SDL_PollEvent(&event))
{
// check for messages
switch (event.type)
{
// exit if the window is closed
case SDL_QUIT:
done = true;
break;
// check for keypresses
case SDL_KEYDOWN:
{
// exit if ESCAPE is pressed
if (event.key.keysym.sym == SDLK_ESCAPE)
done = true;
break;
}
} // end switch
} // end of message processing
// DRAWING STARTS HERE
// clear screen
SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
// draw bitmap
SDL_BlitSurface(bmp, 0, screen, &dstrect);
// DRAWING ENDS HERE
// finally, update the screen :)
SDL_Flip(screen);
} // end main loop
// free loaded bitmap
SDL_FreeSurface(bmp);
// all is well ;)
printf("Exited cleanly\n");
return 0;
}
I think what you're trying to do is in fact a shaped window (parts of the window are transparent depending on a mask that you provide). It seems there's no way to do that with SDL 1.2, however there is a SDL_SetWindowShape function just for this in SDL 1.3 for which you can find a pre-release snapshot here but it's not even in beta yet so I suggest waiting until it's officialy released :)
this is a link to a pretty neat article about development of an older application for Mac OS 9, which did not have support for shaped windows, either.
It's actually a neat article in general about software development.
But the idea seems pretty smart, and I wonder if you might be able to get it working here, too. Instead of trying to make a transparent background, they actually take a screen-shot of the computer right where their window is going to go, and then use that screen shot for their background. When the user drags the window around on the screen, they continue to update the background with new screen-shots. I think this might be more complicated than you were hoping for, but it's certainly an interesting idea.