SDL: IMG_load returns wrong data - sdl

The problem comes from the "IMG_load" fonction of the SDL_image, with language C.
It raises no error during execution, but when it comes to the line
SDL_Surface* image1 = IMG_Load("image.bmp");
the function returns a data that I can't use: for instance, SDL_BlitSurface(image1, NULL, screen, &position) won't do anything.
However, it works fine when using the function SDL_LoadBMP.
I have used the debugger to try to understand the difference between the data returned by the two functions:
Here is what IMG_Load("image.bmp") returns:
{ //Doesn't work
flags = 0,
format = 0x3c07c0,
w = 40,
h = 40,
pitch = 120,
pixels = 0x3c07f0,
offset = 0,
hwdata = 0x0,
clip_rect = {
x = 0,
y = 0,
w = 0,
h = 0
},
unused1 = 0,
locked = 40,
map = 0x28,
format_version = 3939000,
refcount = 1
}
And here is what SDL_LoadBMP("image.bmp") returns:
{ //Works fine
flags = 0,
hwdata = 0x0,
clip_rect = {
x = 0,
y = 0,
w = 40,
h = 40
},
unused1 = 0,
locked = 0,
map = 0x3458e8,
format_version = 7,
refcount = 1
}
(Note that the image is the same, and it is a 40x40px square).
Why can't I use SDL_BlitSurface on a SDL_Surface returned by the function IMG_Load?
edit: you also have to know that this is the first time a function from the SDL_Image package is used in the program.

Related

Convert Gdiplus::Region to ID2D1Geometry* for clipping

I am trying to migrate my graphics interface project from Gdiplus to Direct2D.
Currently, I have a code that calculates clipping area for an rendering object:
Graphics g(hdc);
Region regC = Rect(x, y, cx + padding[2] + padding[0], cy + padding[3] + padding[1]);
RecursRegPos(this->parent, &regC);
RecursRegClip(this->parent, &regC);
g.setClip(g);
...
inline void RecursRegClip(Object *parent, Region* reg)
{
if (parent == CARD_PARENT)
return;
if (parent->overflow != OVISIBLE)
{
Rect regC(parent->getAbsoluteX(), parent->getAbsoluteY(), parent->getCx(), parent->getCy()); // Implementation of these function is not necceassary
GraphicsPath path;
path.Reset();
GetRoundRectPath(&path, regC, parent->borderRadius[0]);
// source https://stackoverflow.com/a/71431813/15220214, but if diameter is zero, just plain rect is returned
reg->Intersect(&path);
}
RecursRegClip(parent->parent, reg);
}
inline void RecursRegPos(Object* parent, Rect* reg)
{
if (parent == CARD_PARENT)
return;
reg->X += parent->getX() + parent->padding[0];
reg->Y += parent->getY() + parent->padding[1];
if (parent->overflow == OSCROLL || parent->overflow == OSCROLLH)
{
reg->X -= parent->scrollLeft;
reg->Y -= parent->scrollTop;
}
RecursRegPos(parent->parent, reg);
}
And now I need to convert it to Direct2D. As You may notice, there is no need to create Graphics object to get complete calculated clipping region, so I it would be cool if there is way to just convert Region to ID2D1Geometry*, that, as far, as I understand from msdn article need to create clipping layer.
Also, there is probably way to convert existing code (RecursRegClip, RecursRegPos) to Direct2D, but I am facing problems, because I need to work with path, but current functions get region as an argument.
Update 1
There is Region::GetData method that returns, as I understand array of points, so maybe there is possibility to define either ID2D1PathGeometry or ID2D1GeometrySink by points?
Update 2
Oh, maybe
ID2D1GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT32 pointsCount)
is what do I need?
Unfortunately, GetData of region based on just (0,0,4,4) rectangle returns 36 mystique values:
Region reg(Rect(0, 0, 4, 4));
auto so = reg.GetDataSize();
BYTE* are = new BYTE[so];
UINT fi = 0;
reg.GetData(are, so, &fi);
wchar_t ou[1024]=L"\0";
for (int i = 0; i < fi; i++)
{
wchar_t buf[10] = L"";
_itow_s(are[i], buf, 10, 10);
wcscat_s(ou, 1024, buf);
wcscat_s(ou, 1024, L", ");
}
// ou - 28, 0, 0, 0, 188, 90, 187, 128, 2, 16, 192, 219, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 64, 0, 0, 128, 64,
I rewrote the solution completely, it seems to be working:
// zclip is ID2D1PathGeometry*
inline void Render(ID2D1HwndRenderTarget *target)
{
ID2D1RoundedRectangleGeometry* mask = nullptr;
ID2D1Layer* clip = nullptr;
if(ONE_OF_PARENTS_CLIPS_THIS || THIS_HAS_BORDER_RADIUS)
{
Region reg = Rect(x, y, cx + padding[2] + padding[0], cy + padding[3] + padding[1]);
RecursRegPos(this->parent, &reg);
D2D1_ROUNDED_RECT maskRect;
maskRect.rect.left = reg.X;
maskRect.rect.top = reg.Y;
maskRect.rect.right = reg.X + reg.Width;
maskRect.rect.bottom = reg.Y + reg.Height;
maskRect.radiusX = this->borderRadius[0];
maskRect.radiusY = this->borderRadius[1];
factory->CreateRoundedRectangleGeometry(maskRect, &mask);
RecursGeoClip(this->parent, mask);
target->CreateLayer(NULL, &clip);
if(zclip)
target->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), zclip), clip);
else
target->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), mask), clip);
SafeRelease(&mask);
}
// Draw stuff here
if (clip)
{
target->PopLayer();
SafeRelease(&clip);
SafeRelease(&mask);
SafeRelease(&zclip);
}
}
...
inline void RecursGeoClip(Object* parent, ID2D1Geometry* geo)
{
if (parent == CARD_PARENT)
return;
ID2D1RoundedRectangleGeometry* maskParent = nullptr;
if (parent->overflow != OVISIBLE)
{
Rect regC(parent->getAbsoluteX(), parent->getAbsoluteY(), parent->getCx(), parent->getCy());
ID2D1GeometrySink* sink = nullptr;
ID2D1PathGeometry* path = nullptr;
SafeRelease(&path);
factory->CreatePathGeometry(&path);
D2D1_ROUNDED_RECT maskRect;
maskRect.rect.left = regC.X;
maskRect.rect.top = regC.Y;
maskRect.rect.right = regC.X + regC.Width;
maskRect.rect.bottom = regC.Y + regC.Height;
maskRect.radiusX = parent->borderRadius[0];
maskRect.radiusY = parent->borderRadius[1];
path->Open(&sink);
factory->CreateRoundedRectangleGeometry(maskRect, &maskParent);
geo->CombineWithGeometry(maskParent, D2D1_COMBINE_MODE_INTERSECT, NULL, sink);
sink->Close();
SafeRelease(&sink);
SafeRelease(&this->zclip);
this->zclip = path;
RecursGeoClip(parent->parent, this->zclip);
}
else
RecursGeoClip(parent->parent, geo);
SafeRelease(&maskParent);
}
Now I can enjoy drawing one image and two rectangles in more than 60 fps, instead of 27 (in case of 200x200 image size, higher size - lower fps) with Gdi+ -_- :

DirectX 9 cannot change resolution

I'm trying to change the window resolution like this:
pp.hDeviceWindow = hWnd;
pp.Windowed = true;
pp.BackBufferWidth = s.x;
pp.BackBufferHeight = s.y;
pp.BackBufferCount = 1;
pp.EnableAutoDepthStencil = true;
pp.AutoDepthStencilFormat = D3DFMT_D16;
pp.SwapEffect = D3DSWAPEFFECT_FLIP;
pp.BackBufferFormat = D3DFMT_R5G6B5;
m_pDevice->Reset(&pp);
Previously I resize window like this:
SetWindowPos(g_Window, HWND_TOPMOST, 0, 0, 521, 300, SWP_NOMOVE);
But reset always returns INVALID_CALL. What am I doing wrong?
This usually happens when you didn't dispose all you resources (vertex buffer, texture, ...)

Seg Fault when calling SDL_BlitSurface a second time

I'm using SDL and SDL_Image to load images to be used as textures for opengl.
I'm trying to load a spritesheet with multiple images arranged in a horizontal row (in the same image)
void load_spritesheet(std::string key, const char *file_name, int width, int height, int nframes) {
GLuint *texture = new GLuint[nframes];
auto src = IMG_Load(file_name);
auto dstrect = new SDL_Rect{0, 0, width, height};
for(int i = 0; i < nframes; i++) {
auto dst = SDL_CreateRGBSurface(0, width, height, 1, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask);
auto rect = new SDL_Rect { i*width, 0, width, height };
SDL_BlitSurface(src, rect, dst, dstrect);
load_gltex(dst, &texture[i]);
SDL_FreeSurface(dst);
}
SPRITESHEET_CACHE[key] = texture;
SDL_FreeSurface(src);
}
I stepped through the code, and on the first iteration of the loop it works fine. On the second iteration I get a seg fault on the call to SDL_BlitSurface, none of the pointers passed in are NULL and none of the surfaces are locked or anything like that. I'm sure that my rectangles are within the bounds of each surface.
Here's some values from gdb at the point right before it segfaults:
print i
1
print *src
{flags = 0, format = 0x847100, w = 416, h = 32, pitch = 1664, pixels = 0x87c5f0, userdata = 0x0, locked = 0, lock_data = 0x0, clip_rect = {x = 0, y = 0, w = 416, h = 32}, map = 0x8537b0, refcount = 1}
print *dst
{flags = 0, format = 0x855ec0, w = 32, h = 32, pitch = 4, pixels = 0x84d1f0, userdata = 0x0, locked = 0, lock_data = 0x0, clip_rect = {x = 0, y = 0, w = 32, h = 32}, map = 0x6bdfc0, refcount = 1}
print *rect
{x = 32, y = 0, w = 32, h = 32}
print *dstrect
{x = 0, y = 0, w = 32, h = 32}
Is it unsafe to call SDL_BlitSurface twice on the same surface or something like that? Thanks.
Ah, the error was caused by improperly setting the depth on the call to SDL_CreateRGBSurface
I was passing in a 1 when I really should've been passing the correct value (32 in this case)
Once I corrected that the segfault went away.
https://wiki.libsdl.org/SDL_CreateRGBSurface#Remarks

Why the value of trackbar of SADWinowSize_slider become 0 when it assign to sbm->state.SADWindowSize, in my code

I am testing stereoBM tuning parameters by GUI using opencv.
Below is my code.
Mat out1, out2;
Size imageSize = out1.size();
StereoBM sbm;
/// Initialize values
int preFilterType_slider = 0, preFilterCap_slider = 0, preFilterSize_slider = 0,
minDisparity_slider = 0, uniqnessRatio_slider = 0, textureThreshold_slider = 0,
speckleRange_slider = 0, sADWindowSize_slider = 5, spackleWindowSize_slider = 0,
numDisparities_slider = 0, numDisparities2_slider = 0;
int preFilterType_max = 1, preFilterCap_max = 61, preFilterSize_max = 100,
minDisparity_max = 200, uniqnessRatio_max = 2500, textureThreshold_max = 10000,
speckleRange_max = 500, sADWindowSize_max = 255, spackleWindowSize_max = 200,
numDisparities_max = 500, numDisparities2_max = 0;
Mat dispt, disp8, g1, g2;
void on_trackbar_bmTunning(int , void*)
{
if (preFilterSize_slider % 2 == 0) preFilterSize_slider++; //odd
if (preFilterSize_slider < 5) preFilterSize_slider = 5; //started from 5
if (preFilterSize_slider > 255) preFilterSize_slider = 255; // to 255
if (preFilterCap_slider < 1) preFilterCap_slider = 1;
if (preFilterCap_slider > 63) preFilterCap_slider = 63;
if (sADWindowSize_slider % 2 == 0) sADWindowSize_slider++;
if (sADWindowSize_slider <= 5) sADWindowSize_slider = 5;
if (sADWindowSize_slider > 255)sADWindowSize_slider = 255;
if (sADWindowSize_slider >= MIN(imageSize.width, imageSize.height))
sADWindowSize_slider = MIN(imageSize.width, imageSize.height);
if (minDisparity_slider < 0) minDisparity_slider = 0;
if (numDisparities_slider <1) numDisparities_slider = 1;
if (textureThreshold_slider < 0) textureThreshold_slider = 1;
if (uniqnessRatio_slider < 0) uniqnessRatio_slider = 1;
//disp8 = g1.clone();
sbm.state->speckleWindowSize = spackleWindowSize_slider;
sbm.state->speckleRange = speckleRange_slider;
sbm.state->preFilterSize = preFilterSize_slider; // 41
sbm.state->preFilterCap = preFilterCap_slider; //31
sbm.state->SADWindowSize = sADWindowSize_slider; //41
sbm.state->minDisparity = minDisparity_slider *-16;//-64
sbm.state->numberOfDisparities = numDisparities_slider * 16; //128
sbm.state->textureThreshold = textureThreshold_slider; //10
sbm.state->uniquenessRatio = uniqnessRatio_slider; //15
sbm(g1, g2, dispt);
normalize(dispt, disp8, 0, 255, CV_MINMAX, CV_8U);
imshow("Tune BM Window ", disp8);
}
int test2_bmTunning() {
out1 = imread("aloeL.jpg");
out2 = imread("aloeR.jpg");
cvtColor(out1, g1, CV_BGR2GRAY);
cvtColor(out2, g2, CV_BGR2GRAY);
namedWindow("Tune BM Window", CV_WINDOW_NORMAL);
createTrackbar("Number of Disparities", "Tune BM Window", &preFilterType_slider, preFilterType_max, 0);
createTrackbar("Pre Filter Cap", "Tune BM Window", &preFilterCap_slider, preFilterCap_max, on_trackbar_bmTunning);
createTrackbar("Pre Filter Size", "Tune BM Window", &preFilterSize_slider, preFilterSize_max, on_trackbar_bmTunning);
createTrackbar("Minimum Disparity", "Tune BM Window", &minDisparity_slider, minDisparity_max, on_trackbar_bmTunning);
createTrackbar("Uniqueness Ratio", "Tune BM Window", &uniqnessRatio_slider, uniqnessRatio_max, on_trackbar_bmTunning);
createTrackbar("Texture Threshold", "Tune BM Window", &textureThreshold_slider, textureThreshold_max, on_trackbar_bmTunning);
createTrackbar("Speckle Range", "Tune BM Window", &speckleRange_slider, speckleRange_max, on_trackbar_bmTunning);
createTrackbar("Block Size", "Tune BM Window", &sADWindowSize_slider, sADWindowSize_max, on_trackbar_bmTunning);
createTrackbar("Speckle Window Size", "Tune BM Window", &spackleWindowSize_slider, spackleWindowSize_max, on_trackbar_bmTunning);
createTrackbar("Number of Disparity", "Tune BM Window", &numDisparities_slider, numDisparities_max, on_trackbar_bmTunning);
/// Show some stuff
//on_trackbar_bmTunning(sADWindowSize_slider, 0);
waitKey(0);
return 0;
}
Problem :
The problem occurs when the value of SADWindowSlize value from trackbar slider is assigned to sbm.state->SADWindowSize = sADWindowSize_slider; //41
In this line of code, the value of sADWindowSize_slider becomes 0 and so it throws a run time error that SAD window size should be odd and in between 5 to 255.
I am not able to understand how the value of SADWindowSize_slider becomes 0..
Please guide me in finding the reason for this and help me in solving the problem.
thanks
We found problem in our code.
SADWindowSize should be odd and in between 5 ~ 255.
Therefore, this condition is not needed and also not make sense.
if (sADWindowSize_slider >= MIN(imageSize.width, imageSize.height))
sADWindowSize_slider = MIN(imageSize.width, imageSize.height);
Just delete above mentioned line of code, run and tune parameters for your iamge and enjoy result.
Have Fun!!

SDL / C++: How to make this function short(er)?

I have this:
void showNumbers(){
nrBtn1 = TTF_RenderText_Blended( fontnrs, "1", sdlcolors[0] );
nrBtn2 = TTF_RenderText_Blended( fontnrs, "2", sdlcolors[1] );
nrBtn3 = TTF_RenderText_Blended( fontnrs, "3", sdlcolors[2] );
nrBtn4 = TTF_RenderText_Blended( fontnrs, "4", sdlcolors[3] );
nrBtn5 = TTF_RenderText_Blended( fontnrs, "5", sdlcolors[4] );
nrBtn6 = TTF_RenderText_Blended( fontnrs, "6", sdlcolors[5] );
nrBtn7 = TTF_RenderText_Blended( fontnrs, "7", sdlcolors[6] );
nrBtn8 = TTF_RenderText_Blended( fontnrs, "8", sdlcolors[7] );
nrBtn9 = TTF_RenderText_Blended( fontnrs, "9", sdlcolors[8] );
SDL_Rect rcnrBtn1 = { 40, 32, 0, 0 };
SDL_Rect rcnrBtn2 = { 70, 32, 0, 0 };
SDL_Rect rcnrBtn3 = { 100, 32, 0, 0 };
SDL_Rect rcnrBtn4 = { 130, 32, 0, 0 };
SDL_Rect rcnrBtn5 = { 160, 32, 0, 0 };
SDL_Rect rcnrBtn6 = { 190, 32, 0, 0 };
SDL_Rect rcnrBtn7 = { 220, 32, 0, 0 };
SDL_Rect rcnrBtn8 = { 250, 32, 0, 0 };
SDL_Rect rcnrBtn9 = { 280, 32, 0, 0 };
SDL_BlitSurface(nrBtn1, NULL, screen, &rcnrBtn1); SDL_FreeSurface(nrBtn1);
SDL_BlitSurface(nrBtn2, NULL, screen, &rcnrBtn2); SDL_FreeSurface(nrBtn2);
SDL_BlitSurface(nrBtn3, NULL, screen, &rcnrBtn3); SDL_FreeSurface(nrBtn3);
SDL_BlitSurface(nrBtn4, NULL, screen, &rcnrBtn4); SDL_FreeSurface(nrBtn4);
SDL_BlitSurface(nrBtn5, NULL, screen, &rcnrBtn5); SDL_FreeSurface(nrBtn5);
SDL_BlitSurface(nrBtn6, NULL, screen, &rcnrBtn6); SDL_FreeSurface(nrBtn6);
SDL_BlitSurface(nrBtn7, NULL, screen, &rcnrBtn7); SDL_FreeSurface(nrBtn7);
SDL_BlitSurface(nrBtn8, NULL, screen, &rcnrBtn8); SDL_FreeSurface(nrBtn8);
SDL_BlitSurface(nrBtn9, NULL, screen, &rcnrBtn9); SDL_FreeSurface(nrBtn9);
}
But for 60 buttons. Is there a way how to do something like:
void showNumbers()
{
SDL_Rect rcnrBtn1 = { 40, 32, 0, 0 };
SDL_Rect rcnrBtn2 = { 70, 32, 0, 0 };
SDL_Rect rcnrBtn3 = { 100, 32, 0, 0 };
SDL_Rect rcnrBtn4 = { 130, 32, 0, 0 };
SDL_Rect rcnrBtn5 = { 160, 32, 0, 0 };
SDL_Rect rcnrBtn6 = { 190, 32, 0, 0 };
SDL_Rect rcnrBtn7 = { 220, 32, 0, 0 };
SDL_Rect rcnrBtn8 = { 250, 32, 0, 0 };
SDL_Rect rcnrBtn9 = { 280, 32, 0, 0 };
for(int x=1; x<=60;x++){
nrBtn+x = TTF_RenderText_Blended( fontnrs, x, sdlcolors[x-1] );
SDL_BlitSurface(nrBtn+x, NULL, screen, &rcnrBtn+x); SDL_FreeSurface(nrBtn+x);
}
}
You need to use an array.
E.g.
SDL_Rect rcnrBtn[60];
for(int x = 0; x < 60; x++) {
rcnrBtn[x].x = 30 * x + 10;
rcnrBtn[x].y = 32;
rcnrBtn[x].w = 100;
rcnrBtn[x].h = 24;
}
Arrays always start at 0, and this particular one ends at 59 giving a total of 60 elements.
You could do something like this :
void showNumbers() {
SDL_Surface* nrBtn = NULL;
int nbr = 1;
int x = 30; // your starting x
int i = 0;
for (; i < 60; ++i) {
nrBtn = TTF_RenderText_Blended(fontnrs, nbr_to_str(nbr), sdlcolors[i]); // You'll have to code nbr_to_str
SDL_Rect rect = {x, 32, 0, 0}; // Are you sure that width and height are 0 ?
SDL_BlitSurface(nrBtn, NULL, screen, &rect);
SDL_FreeSurface(nrBtn);
x += 30;
}
return;
}
It appears your entire function could be replaced with the following array-based variation. Assuming that your nrBtnXX variables are defined outside the function and you want to minimise the scope of changes, you should look at something like:
#define BUTTON_COUNT 60
SDL_Surface *nrBtn[BUTTON_COUNT];
void showNumbers () {
char textNum[3];
for (int i = 0; i < BUTTON_COUNT; i++) {
sprintf (textNum, "%d", i);
nrBtn[i] = TTF_RenderText_Blended( fontnrs, textNum, sdlcolors[i] );
}
SDL_Rect rcnrBtn[BUTTON_COUNT];
for (int i = 0; i < BUTTON_COUNT; i++) {
rcnrBtn[i].x = 40 + i * 30; // use formulae for all these.
rcnrBtn[i].y = 32;
rcnrBtn[i].w = 0;
rcnrBtn[i].h = 0;
}
for (int i = 0; i < BUTTON_COUNT; i++) {
SDL_BlitSurface(nrBtn[i], NULL, screen, &rcnrBtn[i]);
SDL_FreeSurface(nrBtn[i]);
}
}
The idea is to store everything in arrays so that you don't have to deal with individual variables. If the nrBtn variables are required to be a non-array, then I would set up a single array of pointers to them so this approach would still work, something like:
SDL_Surface *nrBtnPtr[] = { &nrBtn1, &nrBtn2 ..., &nrBtn60 };
You should also set the formulae intelligently for the x and y coordinates since you probably don't want a 60x1 matrix for them. Look into making it 12x5 or something equally as compact.