I have a small script which is meant to get the user's screen resolution and assign it to a variable but i get an Access Violation error and not sure how to fix it (I'm quite new to this language) so was hoping some one can show me how I should write it.
This is my setup:
//get player's screen info
const SDL_VideoInfo* myScreen = SDL_GetVideoInfo();
//SDL screen
SDL_Surface *screen;
int reso_x = myScreen->current_w; //resolution width (ERROR here)
int reso_y = myScreen->current_h; //resolution height
Uint8 video_bpp = 32;
Uint32 videoflags = SDL_SWSURFACE | SDL_DOUBLEBUF | SDL_ANYFORMAT;// | SDL_FULLSCREEN;
/* Initialize the SDL library */
if ( SDL_Init(videoflags) < 0 ) {
fprintf(stderr, "Couldn't initialize SDL: %s\n",
SDL_GetError());
exit(1);
}
//setup Screen
screen = SDL_SetVideoMode(reso_x, reso_y, video_bpp, videoflags|SDL_FULLSCREEN);
Does any one know the cause of my mistake?
You shouldn't make any SDL calls before SDL_init. My guess is GetVideoInfo is returning null because you are not in a valid state at that point. Also the flags you are passing to init are wrong, it should be SDL_INIT_VIDEO not what kind of video you want. Your video flags should go to the SetVideoMode function.
Related
So I'm trying to iron out kinks of how I'm rendering images with direct stuff. Right now it works as a DXGISwapchain with D3D11 and I make a ID2D1RenderTarget which I draw to using bitmaps. My issue is when I hit the maximize button on the window my images are off, or at least the ones using data from the window grabbed with GetClientRect (the others seem... close enough but probably still off and I want to be able to use the client space to scale and draw things later as well). I have a D2D1::RectF set with the top left at 0.0f and the bottom right as the window's height and width grabbed via GetClientRect (along with a few others just for additional fooling around). Looked around and it seems like I need to call recreate the ID2D1RenderTarget and/or resize the buffers. Calling a function to recreate the ID2D1RenderTarget before making objects which contain the bitmaps and the functions which draw them did not help with the issue at all. I tried resizing the buffers but I keep getting errors, first set were regarding parameters, but before fixing that I realized I needed to release the objects, but now my it seems since I have made the objects with ComPtr it seems how it deals with deleting them is having issues. client.h is calling an exception: "Access violation executing location " with the unsigned long InternalRelease() function. This occurs with the function to adjust the buffers and target. So right now I'm lost as to what to do in order to get the desired effect. Only other things to note is the ID3D11RenderTargetView I made is used to clear to a color since for I had errors with calling Clear(D2D1::ColorF(D2D1::ColorF::White)); on my ID2D1RenderTarget. I don't care if the solution to this resizes the ID3D11RenderTargetView unless it will improve speed for the program or prevent some sort of unforeseen issue elsewhere since I don't intend to use it aside for that. If I could call clear on the ID2D1RenderTarget and no longer need the ID311RenderTargetView and keep the swapchain while resolving the issue that would work too. Also I intend to work out fullscreen mode next so a method that works with that would also be very much desired. I'm also open to take any other advice here, while it's not polished and just in a form to get things working first, I probably will miss things even when tidying up. Anyway here's the code:
Here's the Graphics class where I make the swapchain, buffers and rendertargets and such and the function in which I try and reset the buffers. Side note I followed some tutorials on my way here to get me to understand enough of the direct stuff to get here and get to the point where I'm looking into to stuff on Microsoft and understanding it somewhat to solve problems I have. Anyway one of them went through making some exceptions and that is what stuff like Graphic_Throw_Failure() are for. (though I did it wrong or the errors are doing something and I can't see the pop up window half the time, sometimes it stops in the exception code but I can still read the message)
//not in the cpp file but just how some variables exist for clarity.
private:
Microsoft::WRL::ComPtr<ID3D11Device> pDevice = nullptr;
Microsoft::WRL::ComPtr < IDXGISwapChain> pSwapChain = nullptr;
Microsoft::WRL::ComPtr < ID3D11DeviceContext> pContext = nullptr;
Microsoft::WRL::ComPtr < ID3D11RenderTargetView> pRTarget = nullptr;
ID2D1RenderTarget* p2dRenderTarget = nullptr;
ID2D1Factory* p2DFactory = nullptr;
Graphics::Graphics(HWND hwnd) {
DXGI_SWAP_CHAIN_DESC swapchainDesc = {};
ZeroMemory(&swapchainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
swapchainDesc.Windowed = true;
swapchainDesc.BufferCount = 1;
swapchainDesc.BufferDesc.Height = 0;
swapchainDesc.BufferDesc.Width = 0;
swapchainDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapchainDesc.SampleDesc.Count = 1;
swapchainDesc.SampleDesc.Quality = 0;
swapchainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapchainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapchainDesc.BufferDesc.RefreshRate.Numerator = 1;
swapchainDesc.BufferDesc.RefreshRate.Denominator = 60;
swapchainDesc.OutputWindow = hwnd;
HRESULT hre;
Graphic_Throw_Failure(D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
levels,
4,
D3D11_SDK_VERSION,
&swapchainDesc,
&pSwapChain,
&pDevice,
nullptr,
&pContext
));
//3Dbuffer setup
wrl::ComPtr<ID3D11Resource> p3dbuffer = nullptr;
Graphic_Throw_Failure(pSwapChain->GetBuffer(0, __uuidof(ID3D11Resource), &p3dbuffer));
Graphic_Throw_Failure(pDevice->CreateRenderTargetView(p3dbuffer.Get(), nullptr, &pRTarget));
//2D buffer Setup
IDXGISurface* pBackBuffer = nullptr;
Graphic_Throw_Failure(pSwapChain->GetBuffer(0,IID_PPV_ARGS(&pBackBuffer)));
//makes 2d Factory
Graphic_Throw_Failure(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &p2DFactory));
//sets up DXGI buffer for 2d
FLOAT dpi;
dpi = GetDpiForWindow(hwnd);
//p2DFactory->GetDesktopDpi(&dpiX, &dpiY);
D2D1_RENDER_TARGET_PROPERTIES p2dRTprops =
D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
dpi,
dpi
);
Graphic_Throw_Failure(p2DFactory->CreateDxgiSurfaceRenderTarget(
pBackBuffer, &p2dRTprops, &p2dRenderTarget
));
if(pBackBuffer!=nullptr)
pBackBuffer->Release();
}
//the adjusting function I failed to make. could also be missing somethings I need to clear before
//calling ResizeBuffers
void Graphics::adjustRenderTargets(HWND hwnd) {
HRESULT hre;
pContext->ClearState();
p2dRenderTarget->Release();
pRTarget->Release();
//3Dbuffer setup
wrl::ComPtr<ID3D11Resource> p3dbuffer = nullptr;
Graphic_Throw_Failure(pSwapChain->GetBuffer(0, __uuidof(ID3D11Resource), &p3dbuffer));
Graphic_Throw_Failure(pDevice->CreateRenderTargetView(p3dbuffer.Get(), nullptr, &pRTarget));
//2D buffer Setup
IDXGISurface* pBackBuffer = nullptr;
Graphic_Throw_Failure(pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)));
//makes 2d Factory
Graphic_Throw_Failure(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &p2DFactory));
//sets up DXGI buffer for 2d
FLOAT dpi;
dpi = GetDpiForWindow(hwnd);
//p2DFactory->GetDesktopDpi(&dpiX, &dpiY);
D2D1_RENDER_TARGET_PROPERTIES p2dRTprops =
D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
dpi,
dpi
);
Graphic_Throw_Failure(p2DFactory->CreateDxgiSurfaceRenderTarget(
pBackBuffer, &p2dRTprops, &p2dRenderTarget
));
if (pBackBuffer != nullptr)
pBackBuffer->Release();
};
//and the destructor in case there is something still wrong there though
//currently not giving me issues since I set the objects in it to nullptr after releasing it.
//didn't work for the ComPtr.
Graphics::~Graphics() {
if (p2DFactory != nullptr) {
p2DFactory->Release();
}
if (p2dRenderTarget != nullptr) {
p2dRenderTarget->Release();
}
}
This is the class which holds the bitmaps and deals with them and drawing them. Once again I made some exceptions for this class
//some variables in the header file
ID2D1Bitmap* Bittmap=nullptr;
Graphics* GFX;
Sprites::Sprites(const wchar_t* filename, Graphics* gfx) {
HRESULT hre;
GFX = gfx;
//makes WIC Factory
IWICImagingFactory* WICfactory = NULL;
Sprite_Throw_Failure(CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
(LPVOID*)&WICfactory
));
//Makes the Decoder
IWICBitmapDecoder* WICdecode = NULL;
Sprite_Throw_Failure(WICfactory->CreateDecoderFromFilename(
filename,
NULL,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&WICdecode
));
//Read the frame (should be only one so read the image)
IWICBitmapFrameDecode* WICframe = NULL;
Sprite_Throw_Failure(WICdecode->GetFrame(0, &WICframe));
//Format converter
IWICFormatConverter* WICconverter = NULL;
Sprite_Throw_Failure(WICfactory->CreateFormatConverter(&WICconverter));
//makes the converter set up to create a 32bpp BGRA bitmap
Sprite_Throw_Failure(WICconverter->Initialize(
WICframe,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.0,
WICBitmapPaletteTypeCustom
));
//makes the bitmap
Sprite_Throw_Failure(GFX->Get2DRenderTarget()->CreateBitmapFromWicBitmap(
WICconverter,
NULL,
&Bittmap
));
if (WICfactory) WICfactory->Release();
if (WICdecode) WICdecode->Release();
if (WICconverter)WICconverter->Release();
if (WICframe)WICframe->Release();
}
//draws the sprites
void Sprites::Draw(D2D1_RECT_F location) {
HRESULT hre;
GFX->Get2DRenderTarget()->BeginDraw();
GFX->Get2DRenderTarget()->DrawBitmap(
Bittmap,
location, //destination rect
1.0f, //opacity
D2D1_BITMAP_INTERPOLATION_MODE::D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR,
D2D1::RectF(
1980.0f, 2850.0f, 3000.0f,
3600.0f) //source rect
);
Sprite_Throw_Failure(GFX->Get2DRenderTarget()-> EndDraw());
}
Sprites::~Sprites() {
//bitmapsheet.clear();
if (Bittmap != nullptr) {
Bittmap->Release();
}
}
This is the class which the main loop is handled wnd is the windowclass I made which makes and manages the window. I use it here to get the graphics object the window uses which has all the direct stuff. here are some variables that appear, forgive the name bob.
//in header file
private:
Window wnd;
//in cpp file
Sprites* testsprite;
Sprites* testsprite2;
D2D1_RECT_F bob;
within the function that calls over and over for the duration of the program at the part where I render:
//inefficient constant adjusting of rendering just so I can quickly assess
//the change and make sure it works so when I implement how I intend the windows to be scaled it
//will already be done
wnd.GFX().adjustRenderTargets(wnd.getwindowhandle());
//clearing the ID3D11RenderTargetView to a color
wnd.GFX().ClearBuffer(0.3f, 0.5f, 1.0f);
//drawing calls
const wchar_t* filename = L"\environmentsketches 02.png";
//this creates a Sprites object getGraphix returns the a pointer to the graphics object
//only really used to get the ID2D1RenderTarget but I may use it for other things, will
//remove later if not needed and just pass the render target unless issues arise.
testsprite = new Sprites(filename, wnd.GFX().getGraphix());
bob = D2D1::RectF(
0.0f, 0.0f, wnd.getwindowWidth(),
wnd.getwindowHeight());
//This draws the bitmap of a predetermined portion of the image but uses bob to
// to determine where to draw the bitmap
testsprite->Draw(bob);
bob = D2D1::RectF(
0.0f, 0.0f, wnd.getwindowWidth()/(16.0f/9.0f),
wnd.getwindowHeight());
testsprite->Draw(bob);
filename= L"\envrioment sketch march 1.png";
bob = D2D1::RectF(
100.0f, 100.0f, 600.f,
300.f);
testsprite2 = new Sprites(filename, wnd.GFX().getGraphix());
testsprite2->Draw(bob);
//EndFrame just calls present on the IDXGISwapChain
wnd.GFX().EndFrame();
testsprite->~Sprites();
testsprite2->~Sprites();
If you read through this thank you and thank you for any advice you have to offer.
Don't code late or tired. So first thing I realized is one when posting the code here I forgot to include the call for SwapChain->ResizeBuffers(0,width,height, DXGI_FORMAT_UNKNOWN, 0)) which is where the mistake was. I changed my pointers from smart to regular to manage their release manually for this, but the issue was more so that the last parameter wasn't 0, it was D3D11_CREATE_DEVICE_BGRA_SUPPORT instead of a proper swapchain flag and was reading as another (I believe DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY) which I couldn't use because of how I made my swapchain resulting in an error and it just not running.
In all the solution to my problem was to release my render targets (I already released by buffers after I made the targets), resize the buffers and then remake the ID2D1RenderTarget. Just don't put a wrong flag in, (or make sure the call is in when posting it for feedback to the mistake might be caught by others.)
I'm trying to use SDL2 to take a screenshot of the entire desktop in windows. However, when looking at the resulting .bmp file it's completely black. Any help would be appreciated.
Here's my code:
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window* window = SDL_CreateWindowFrom(GetDesktopWindow());
int w, h;
SDL_GetWindowSize(window, &w, &h);
uint32_t wnd_pix_fmt = SDL_GetWindowPixelFormat(window);
if(wnd_pix_fmt == SDL_PIXELFORMAT_UNKNOWN)
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Window pix fmt error", SDL_GetError(), NULL);
SDL_Surface* screenshot = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, wnd_pix_fmt);
if(!screenshot)
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "RGB surface error", SDL_GetError(), NULL);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
if(!renderer)
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Renderer error", SDL_GetError(), NULL);
if(SDL_RenderReadPixels(renderer, &screenshot->clip_rect, screenshot->format, screenshot->pixels, screenshot->pitch))
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "RendererReadPixels error", SDL_GetError(), NULL);
SDL_SaveBMP(screenshot, "screenshot.bmp");
SDL_FreeSurface(screenshot);
NOTE: Even when I set SDL_Window* window to a window created with SDL_CreateWindow it's still completely black. On a different forum, they mentioned this may have to do with a double buffering issue. I'm unaware of how to solve such an issue though.
You have a fundamental misconception of what SDL_RenderReadPixels() does. Indeed it is used to take "screenshots", but the "screenshot" will be of what you have rendered using that specific renderer, nothing else. You will not be able to accomplish what you want using anything available in SDL.
Taking a screenshot of the entire screen typically requires elevated permissions (I have no idea about Windows) and is outside the scope of SDL.
I'm trying to learn SDL 2.0 and I've been following lazyfoo tutorials. The problem is that those tutorials keeps everything in one file. So I tried to split some things up when starting a new game-project. My problem is that when I seperated my texture class from the rest it sometimes crashes the program, not always but pretty often.
I have a global window and a global renderer which I'm using in my class. I get segfault at difference places in the program but always in one of the following functions.
bool myTexture::loadFromFile(string path) {
printf("In loadFromFile\n");
//Free preexisting texture
free();
//The final texture
SDL_Texture *l_newTexture = NULL;
//Load image at specified path
SDL_Surface *l_loadedSurface = IMG_Load(path.c_str());
if(l_loadedSurface == NULL) {
printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError());
} else {
//Color key image for transparancy
//SDL_SetColorKey(l_loadedSurface, SDL_TRUE, SDL_MapRGB(l_loadedSurface->format, 0, 0xFF, 0xFF));
//Create texture from surface pixels
l_newTexture = SDL_CreateTextureFromSurface(g_renderer, l_loadedSurface);
if(l_newTexture == NULL) {
printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
} else {
//Get image dimensions
m_width = l_loadedSurface->w;
m_height = l_loadedSurface->h;
}
//Get rid of old loaded surface
SDL_FreeSurface(l_loadedSurface);
}
m_texture = l_newTexture;
//return success
printf("end from file \n");
return m_texture != NULL;
}
void myTexture::free() {
printf("In myTexture::free\n");
//Free texture if it exist
if(m_texture != NULL) {
cout << (m_texture != NULL) << endl;
SDL_DestroyTexture(m_texture);
printf("Destroyed m_texture\n");
m_texture = NULL;
m_width = 0;
m_height = 0;
}
printf("end free\n");
}
After reading on SDL and other stuffs I understood that there might be some thread trying to deallocate something which it isn't allowed to deallocate. However I haven't threaded anything yet.
I managed to solve this by my own. It turned out that I never created a new myTexture object which was really idiotic. But I still don't understand how it managed to render it sometimes... for me it don't make any sense at all. I never created it but I could still call its render function sometimes...
I use SDL and libav in C++ to draw a video on the screen in Linux. Most of my code for video opening is based on this tutorial, but I changed some functions that were deprecated. I initialize SDL like this:
SDL_Init(SDL_INIT_EVERYTHING);
const SDL_VideoInfo * info = SDL_GetVideoInfo();
screen = SDL_SetVideoMode(info->current_w, info->current_h, 0, SDL_SWSURFACE | SDL_FULLSCREEN);
I am not going to post the whole code since it is pretty big, but the following shows how I try to display a video overlay. Note that some variables are classmembers from my Video class, like formatCtx and packet.
void Video::GetOverlay(SDL_Overlay * overlay) {
int frameFinished;
while (av_read_frame(formatCtx, &packet) >= 0) {
if (packet.stream_index == videoStream) {
avcodec_decode_video2(codecCtx, frame, &frameFinished, &packet);
if (frameFinished) {
SDL_LockYUVOverlay(overlay);
AVPicture pict;
pict.data[0] = overlay->pixels[0];
pict.data[1] = overlay->pixels[2];
pict.data[2] = overlay->pixels[1];
pict.linesize[0] = overlay->pitches[0];
pict.linesize[1] = overlay->pitches[2];
pict.linesize[2] = overlay->pitches[1];
SwsContext * ctx = sws_getContext (codecCtx->width, codecCtx->height, codecCtx->pix_fmt,
codecCtx->width, codecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(ctx, frame->data, frame->linesize, 0, codecCtx->height, pict.data, pict.linesize);
sws_freeContext(ctx);
SDL_UnlockYUVOverlay(overlay);
++frameIndex;
return;
}
}
av_free_packet(&packet);
}
}
And then in my mainloop:
SDL_Overlay * overlay = SDL_CreateYUVOverlay(video->GetWidth(), video->GetHeight(), SDL_YV12_OVERLAY, screen);
while (true) {
video->GetOverlay(overlay);
SDL_Rect rect = { 400, 200, video->GetWidth(), video->GetHeight() };
SDL_DisplayYUVOverlay(overlay, &rect);
SDL_Flip(screen);
}
This works, the video plays but it flickers a lot. Like it tries to draw an image on the same place each frame. When I remove the call to SDL_Flip(screen) the video plays fine. Too fast, I haven't worked videotiming out yet, but when I add a temporary SDL_Delay(10) it looks pretty good.
But when I remove SDL_Flip to show my video, I can't draw anything else on the screen. Both SDL_BlitSurface and SDL_FillRect fail to draw anything on the screen. I already tried to add SDL_DOUBLEBUF to the flags, but this did not change the situation.
I can provide more code if that is needed, but I think the problem is somewhere in the code that I have posted, since everything else is working fine (drawing images, or displaying a video without SDL_Flip).
What am I doing wrong?
Since you're using a SWSURFACE don't use SDL_Flip(screen) use SDL_UpdateRect. You don't need to set SDL_DOUBLEBUF
http://sdl.beuc.net/sdl.wiki/SDL_UpdateRect
That's what I do and I don't get flicker.
I set my screen like this
screen = SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE | SDL_FULLSCREEN);
In my main loop I call
SDL_UpdateRect(screen, 0, 0, 0, 0);
You should use double buffering to prevent flickering.
screen = SDL_SetVideoMode(info->current_w, info->current_h, 0, SDL_SWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF);
I still think this isn't the best solution, but I found something that works!
The command SDL_UpdateRect(screen, 0, 0, 0, 0); will update the whole screen. If I only update the parts of the screen where no video is drawn, the video won't flicker anymore. I think it might have something to do with SDL_Overlays being handled differently than normal surfaces.
I have an application that does not run in full-screen mode.
After SDL_init I execute SDL_SetVideoMode(0, 0, SDL_OPENGL | SDL_HWSURFACE | SDL_ASYNCBLIT). From what I read, this should allocate a window of maximum size.
The unfortunate thing now is that it allocates a window of 1600x900: which is the physical size of the monitor but not the free space on the monitor (some of it is used by the menu-row and by the window-border).
Any ideas how I can find how much space is available?
What I have in my program that runs fullscreen (hiding menus, docks, panels etc) is:
if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) < 0 ) {
throw SDL_GetError();
}
const SDL_VideoInfo* vidinfo = SDL_GetVideoInfo();
int max_w = vidinfo->current_w;
int max_h = vidinfo->current_h;
.
.
.
SDL_Surface *screen = SDL_SetVideoMode(max_w,max_h,0,SDL_FULLSCREEN);
Be sure to call SDL_GetVideoInfo() before SDL_SetVideoMode().