So I have three classes Application, DrawMgr and Cube. In Application.cpp is my main loop in which I call DrawMgr::DrawCube in which I call Cube::Draw.
Application.cpp
while (!quit)
{
//Draw Background
gDrawMgr.DrawBackground();
gDrawMgr.DrawCube();
//UpdateScreen
gDrawMgr.UpdateScreen();
//Handle events on queue
while (SDL_PollEvent(&e) != 0)
{
//User requests quit
if (e.type == SDL_QUIT || e.key.keysym.sym == SDLK_ESCAPE)
{
quit = true;
}
}
}
DrawMgr.cpp
SDL_Surface* screenSurface;
void DrawMgr::DrawCube()
{
gCube.Draw(screenSurface);
}
Cube.cpp
void Cube::Draw( SDL_Surface* destination )
{
SDL_Rect offset;
offset.x = 100;
offset.y = 100;
SDL_FillRect(cube, NULL, SDL_MapRGB( cube->format, 0, 0, 0 ) );
SDL_BlitSurface( cube, NULL, destination, &offset);
}
When I run the program, the cube doesn't appear, what am I doing wrong?
Are you sure you're using SDL2.0 ? because things have changed, you need a SDL_Renderer and a SDL_Texture. Seems like you're trying to do it in the SDL 1 way.
In SDL2, to update the screen, we use those calls
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
SDL_RenderPresent(sdlRenderer);
RenderClear to wipe the screen content.
RenderCopy to draw some texture on it.
RenderPresent to draw the final result on the screen.
Go see the migration guide for more details on the new flow.
https://wiki.libsdl.org/MigrationGuide
Related
I'm just trying to create a simple SDL2 window with a simple renderer. When I debug it, it runs normally, the memory still normal. But when I minimize it, press the minimize button then suddenly the memory just keep going up and only when i reopened that window then the memory goes back normal.
Memory spike
The code:
#include <SDL.h>
#include <SDL_image.h>
int main(int argc, char* args[]) {
SDL_Window* gWindow;
SDL_Renderer* gRenderer;
SDL_Texture* gTexture;
SDL_Surface* temp;
//Init
SDL_Init(SDL_INIT_VIDEO);
gWindow = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1366, 768, SDL_WINDOW_SHOWN);
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
IMG_Init(IMG_INIT_PNG);
//loading medias
temp = IMG_Load("assets/sprites/700.png");
gTexture = SDL_CreateTextureFromSurface(gRenderer, temp);
SDL_FreeSurface(temp);
//The main loop
bool quit = false;
SDL_Event e;
while (!quit)
{
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
quit = true;
}
}
SDL_RenderClear(gRenderer);
SDL_RenderCopy(gRenderer, gTexture, NULL, NULL);
SDL_RenderPresent(gRenderer);
}
//Destroy things
SDL_DestroyTexture(gTexture);
gTexture = NULL;
SDL_DestroyRenderer(gRenderer);
SDL_DestroyWindow(gWindow);
gWindow = NULL;
gRenderer = NULL;
IMG_Quit();
SDL_Quit();
return 0;
}
switch (m_event.window.event)
{
case SDL_WINDOWEVENT_MINIMIZED:
while (SDL_WaitEvent(&m_event))
{
if (m_event.window.event == SDL_WINDOWEVENT_RESTORED)
{
break;
}
}
break;
...
So when you minimize the Window, SDL keeps waiting for events. No further code could memory leak, since it stays in the lazy polling loop until the window is restored.
I traced the leak back to SDL_RenderClear, which shouldn't be supposed to run while minimized.
I just ran your code and compiled it. Seems fine. However you did mention when you minimize the program your ram meter increases, how long are you able to perform this repetition before it crashes? and does it even crash? It could be normal behavior. If your program crashes, its a memory leak which could indicate forgetting to de-allocate some other pointer to a memory object/variable.
i stuck in a big bug with my code which i can't open the first window of my game after running it! it just open blank for a few secondes and then it closes automatically. I doon't know what wrong with my code beacause i'm following series of tutorials and my code seems like the code in the tutorials. here's my code:
#include "stdafx.h"
#include "FirstClass.h"
FirstClass::FirstClass(void){
bool quit = false;
window = NULL;
window = SDL_CreateWindow("Snaykie v1.0",350, 150, 800, 500, SDL_WINDOW_SHOWN);
if (window == NULL){
std::cout << "Can not open the game!" << std::endl;
}
renderer = NULL;
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
evt = new SDL_Event();
//background image
txt = NULL;
txt = IMG_LoadTexture(renderer, "mainview.bmp");
rct.x = 0 ;
rct.y = 0;
rct.h = 500;
rct.w = 800;
//button start
sbutt = NULL;
sbutt = IMG_LoadTexture(renderer, "startbutton.bmp");
startrct.x = 0 ;
startrct.y = 0;
startrct.h = 100;
startrct.w = 100;
}
FirstClass::~FirstClass(void)
{
SDL_DestroyTexture(txt);
SDL_DestroyTexture(sbutt);
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
delete evt;
}
//the code below is the loops that let the window stucks forever to keep opened
void FirstClass :: GameStart(void){
while (!quit && evt->type != SDL_QUIT){
SDL_PollEvent(evt);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, txt, NULL, &rct);
SDL_RenderCopy(renderer, sbutt, NULL, &startrct);
SDL_RenderPresent(renderer);
}
}
Please help me and thanks i'm really in a big problem.
You are handling the evt variable in a bad way. It is allocated but not initialized, and you compare the uninitialized value to SDL_QUIT. You should reorder the code inside FirstClass::GameStart and preferably use a local variable (since there is no actual need to use a dynamically allocated one) and remove the allocation and deletion of the existing evt from constructor and destructor. Here is a better version of FirstClass::GameStart:
void FirstClass::GameStart(void){
SDL_Event evt;
while (SDL_PollEvent(&evt)){
if (evt.type == SDL_QUIT) {
// a user requested termination has been received, exit the loop
break;
}
else {
// filter the event?
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, txt, NULL, &rct);
SDL_RenderCopy(renderer, sbutt, NULL, &startrct);
SDL_RenderPresent(renderer);
}
}
}
Also ensure that you are actually invoking the FirstClass::GameStart funcion from main, maybe you are simply not running the event loop at all.
I have problems deactivating fullscreen mode with my program. Entering fullscreen happens correctly, but trying to go back to windowed mode doesn't work, the only effect is that the cursor gets shown again.
Here's the MCVE/SSCCE that reproduces the issue for me:
void ToggleFullscreen(SDL_Window* Window) {
Uint32 FullscreenFlag = SDL_WINDOW_FULLSCREEN;
bool IsFullscreen = SDL_GetWindowFlags(Window) & FullscreenFlag;
SDL_SetWindowFullscreen(Window, IsFullscreen ? 0 : FullscreenFlag);
SDL_ShowCursor(IsFullscreen);
}
int main() {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* Window = SDL_CreateWindow("",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
bool Exit = false;
for (SDL_Event Event; !Exit;) {
SDL_WaitEvent(&Event);
if (Event.type == SDL_KEYDOWN) {
switch (Event.key.keysym.sym) {
case SDLK_f: ToggleFullscreen(Window); break;
case SDLK_q: Exit = true; break;
}
}
}
SDL_DestroyWindow(Window);
SDL_Quit();
}
SDL_SetWindowFullscreen returns 0, as if the operation was successful. What am I doing wrong? (I'm using SDL 2.0.3 on OS X 10.10.3.)
It looks like a known issue. Hopefully the SDL developers will fix it. I found the following bug report.
https://github.com/libsdl-org/SDL/issues/1428
Even now there still appears to be a problem with SDL_SetWindowFullscreen. I tried to add fullscreen functionality to my video player with this function. However, it would randomly crash when transitioning between fullscreen and windowed mode.
I found a temporary work around that appears to be working correctly for now.
SDL_DisplayMode dm;
if (SDL_GetDesktopDisplayMode(0, &dm))
{
printf("Error getting desktop display mode\n");
return -1;
}
if (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYUP:
switch (event.key.keysym.sym)
{
case SDLK_f:
SDL_RestoreWindow(screen); //Incase it's maximized...
SDL_SetWindowSize(screen, dm.w, dm.h + 10);
SDL_SetWindowPosition(screen, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
}
break;
}
}
It's basically "fake" fullscreen. It resizes the window so the client area covers the whole screen and the minimize, maximize, exit buttons are off screen.
Hope this helps.
I know this may be 5 years after date, but I was facing the same problem, and I found your code way more complex then need be. So I just wanted to add for however comes here:
//somewhere outside the loop
bool isFullScreen = true;
void toggleFullScreen(SDL_Window* window, bool currentState)
{
isFullScreen = !currentState;
SDL_SetWindowFullscreen(window, !currentState);
SDL_ShowCursor(currentState);
}
just place the isFullscreen at the currenState and you have a good toggle with a keypress event.
This works fine for me in SDL2(pressing f toggles it on/off and q quits):
SDL_Window* window = SDL_CreateWindow("Fullscreen demo", 0, 0, 640, 480, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_Event event;
bool fullScreen = false;
SDL_bool running = SDL_TRUE;
while (running) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
running = SDL_FALSE;
break;
case SDL_KEYDOWN:
if(event.key.keysym.scancode == SDL_SCANCODE_F){
fullScreen = !fullScreen;
if(fullScreen){
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
}
else{
SDL_SetWindowFullscreen(window, 0);
}
}
if(event.key.keysym.scancode == SDL_SCANCODE_Q){
running = SDL_FALSE;
}
break;
default: break;
}
}
// drawing stuff here...
// swap and display buffer
SDL_RenderPresent(renderer);
}
I'm using SDL 2.0 with C++ for 2D graphics, compressed image format loading, sound playback and so on. Consider the following code:
int main(int argc, char *args[])
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
SDL_Window *pWindow = SDL_CreateWindow("Access Violation", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1920, 1080, SDL_WINDOW_FULLSCREEN);
SDL_Renderer *pRenderer = SDL_CreateRenderer(pWindow, -1, SDL_RENDERER_ACCELERATED);
Mix_Init(0);
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048);
Mix_Music *pMusic = Mix_LoadMUS("music.wav");
TTF_Init();
TTF_Font *pFont = TTF_OpenFont("font.ttf", 28);
bool quit = false;
SDL_Event ev;
while(!quit)
{
while(SDL_PollEvent(&ev) != 0)
{
switch(ev.type)
{
case SDL_QUIT:
quit = true;
break;
}
}
SDL_SetRenderDrawColor(pRenderer, 255, 255, 255, 255);
SDL_RenderClear(pRenderer);
for(int i = 0; i < 864; i++)
{
SDL_Color clr = { 0, 0, 0 };
SDL_Surface *pSurface = TTF_RenderText_Solid(pFont, "Hey!", clr);
SDL_Texture *pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);
SDL_Rect dstrect = { (int)(i/27) * 60, (i%27)*40, pSurface->w, pSurface->h };
SDL_RenderCopy(pRenderer, pTexture, 0, &dstrect);
SDL_DestroyTexture(pTexture);
SDL_FreeSurface(pSurface);
}
SDL_RenderPresent(pRenderer);
}
TTF_CloseFont(pFont);
Mix_FreeMusic(pMusic);
SDL_DestroyRenderer(pRenderer);
SDL_DestroyWindow(pWindow);
Mix_CloseAudio();
Mix_Quit();
IMG_Quit();
TTF_Quit();
SDL_Quit();
return 0;
}
What this basically does is that it just initializes SDL, loads a music, loads a font, and fills continuously the whole screen with text. Fine.
But!
If I add this line
...
SDL_Event ev;
Mix_PlayMusic(pMusic, 0);
while(!quit)
...
right here, text redrawing in the cycle
for(int i = 0; i < 864; i++)
{
...
}
starts to behave unpredictably. One of the SDL's function will shoot an access violation, after some time - between 1 and 30 seconds after start. On the other hand, would I omit text redrawing, music is playing fine.
Any ideas? Of course, all return values are checked. I've omitted checks because of the clarity of the code.
EDIT: Typos.
Once again stuck with some code that I can't just figure out how to make work. I am trying to create a SDL surface, load a bitmap image and display it. My code is something like this:
struct Image {
string Name;
SDL_Surface* Surface;
};
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, PSTR lpCmdL, INT nCmdS) {
// Will store our bitmap
Image NewImage;
// Initialization
SDL_Init(SDL_INIT_EVERYTHING);
// Create main window
SDL_Surface *Window = SDL_SetVideoMode(640,480,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
SDL_WM_SetCaption("MyApp", "MyApp");
// Load image and make it compatible
SDL_Surface* Surf_Temp = NULL;
if((Surf_Temp = SDL_LoadBMP("myimage.bmp")) != NULL) {
NewImage.Name = "MyImage";
NewImage.Surface = SDL_DisplayFormat(Surf_Temp);
SDL_FreeSurface(Surf_Temp);
}
// Draw image over the window
if (NewImage.Surface != NULL && Window != NULL) {
SDL_Rect DestR;
DestR.x = 0;
DestR.y = 0;
if (SDL_BlitSurface(NewImage.Surface, NULL, Window, &DestR) == -1) {
MessageBox(NULL, "Error", "Alert", MB_OK);
}
}
// Run
SDL_Event Event;
while(!End) {
while(SDL_PollEvent(&Event)) {
EventsHandler(&Event);
}
}
return 0;
}
Well, the image is loaded correctly. I verified it by getting the NewImage.Surface->w (width), which is the correct bitmap's width. I don't get any error message (SDL_BlitSurface returns 0), so I don't know why the window is still black, no image displayed.
You need to call SDL_Flip to update the screen after you blit to it.
SDL_Flip(Window);
Read about double buffering also.