I'm trying to write a bit of code in which I check to see if the mouse has been clicked on a certain SDL Surface. In the code example below, I have the SDL_Surface background which I am trying to check against the mouse position.
bool checkCollide(int myx, int myy, SDL_Surface* objectOne){
if(myx < objectOne->clip_rect.x) return false;
if(myx > objectOne->clip_rect.x + objectOne->clip_rect.w) return false;
if(myy < objectOne->clip_rect.y) return false;
if(myy > (objectOne->clip_rect.y + objectOne->clip_rect.h)) return false;
return true;
}
void main(){
SDL_Surface* background;
while(SDL_PollEvent(&event)){
if(event.type == SDL_MOUSEBUTTONDOWN){
if(checkCollide(event.button.x, event.button.y, background){
// run events
}
}
}
The problem I'm having is that when I try to run it as shown above, the code compiles fine but doesn't do anything. The collision check always fails. I have tried it in a lot of various combinations, including changing the parameters of checkCollide to SDL_Rect and passing the Surface's clip_rect property. The only completely successful way I've done it is to have a separate SDL_Rect with the same size and location as the SDL_Surface, and to check the collision against that. When I run it that way, it all works as I expect it to. Why isn't the surface (or clip_rect) passing correctly, or if it is, what am I doing wrong in the checkCollide function to cause it to fail?
The clip_rect property is not what you think it is:
From the SDL docs:
The clip_rect field is the clipping rectangle as set by
SDL_SetClipRect.
and SDL_SetClipRect
Sets the clipping rectangle for a surface. When this surface is the
destination of a blit, only the area within the clip rectangle will be
drawn into.
The rectangle pointed to by rect will be clipped to the edges of the
surface so that the clip rectangle for a surface can never fall
outside the edges of the surface.
If rect is NULL the clipping rectangle will be set to the full size of
the surface.
The problem is, that when you test the collision later on, the clip_rect x,y are always set to 0. The surface itself does not know about it's position on the screen.
A solution to this would be to create a Sprite like class that will have a Rect and a Surface.
Related
I'm adding Direct Draw rendering option to my 2D Graphics Engine.
When setting the Direct Draw Clipper on a non fullscreen application clipper clips the client area with an offset if the Window's client area top left position is not on the 0,0 of the screen.
Here is my clipper setup code :
LPDIRECTDRAWCLIPPER directDrawClipper = nullptr;
if (!FAILED(mDirectDraw->CreateClipper(0, &directDrawClipper, NULL))) {
if (!FAILED(directDrawClipper->SetHWnd(0, App->getWindow()->getHandle()))) {
if (!FAILED(mDirectDrawFrontBuffer->SetClipper(directDrawClipper))) {
if (!FAILED(mDirectDrawBackBuffer->SetClipper(directDrawClipper))) {
return true; //all good
} else {
throw Error::Exception(L"DirectDraw arka görüntü bellek tamponu kesicisi kurulamadı",
L"Renderer Kurulum Hatası");
}
} else {
throw Error::Exception(L"DirectDraw ana görüntü bellek tamponu kesicisi kurulamadı",
L"Renderer Kurulum Hatası");
}
} else {
throw Error::Exception(L"DirectDraw kesicisi pencereye kurulamadı",
L"Renderer Kurulum Hatası");
}
} else {
throw Error::Exception(L"DirectDraw kesicisi kurulamadı",
L"Renderer Kurulum Hatası");
}
And here is the screenshot :
the size of the white areas are the distance of client area to the screen upper left corner.
Moving the window to upper left corner of the screen before setting the clipper and moving it back to original position doesn't help.
Thanks in advance.
For the curious I solved the problem with a hack.
Before setting the clipper move the window to a position which the client area of the window will be on 0,0 of the screen. You can use ClientToScreen function to determine the window position which client area will be on the 0,0 of the screen.
After setting up the DirectDraw move the window back to it's original position but there is a problem, if you move the window immediately after setting up the DirectDraw issue persists. (I believe clipper setting functions works async). To solve that you can set a windows timer , right after setting the DirectDraw set a timer (1 second got the job done in my case) and move window back to it's original position when the timer updates.
To summarize the process :
Move window to a new position which client area of the window will be on the 0,0 of the screen.
Set up the clipper
Set a timer (1 second worked in my case)
When timer updates move window back the it's original position.
But still if someone knows the proper solution it would be nice.
I am new to MFC trying to learn from the scratch.
I am trying to create a small dialog based application in VS2012 - MFC.
On the dialog window i have drawn a rectangle (in OnPaint event) like this.
CPaintDC dc(this);
CRect background1(10,10,208,92);
dc.Rectangle(10,10,208,92);
Then i filled the bacground with some color. Like this.
CBrush brush1;
brush1.CreateSolidBrush(RGB(2,3,4));
dc.FillRect(background1,&brush1);
Now i wanted to draw waves in form of pixels continuously inside the rectangle.
As of now what i have done is,
bool top = false;
for(i=10,j=92;i<200 && j>10;)
{
pDC->SetPixel(i,j,NewColor);
Sleep(10);
if(!top)
j-=1;
else
j+=1;
if(j%4==0)
{
i+=1;
}
if(j==12)
top=true;
if(j==90)
top = false;
}
I am just drawing the pixels straightaway on the window, but within the dimensions where the rectangle lies. And the waves stop as it reaches the right dimension of the rect. But i feel thats not the right way to do it.
I want to draw the waves inside the rectangle and also continuosly, like when it reacahes the right end it should move left and it should be continuous.
Is there any proper way in MFC to draw something inside a rectangle (technically inside another object)?
Please help me out.
The ScrollWindow function can be used to scroll the existing graph to the left. Then you draw the new data to the right of the scrolled area. The drawing will be much faster if you use the Polyline function instead of DrawPixel: Polyline draws an array of pixels.
I tried your code and just added some condition, so that if it reaches right side it should start moving toward left.
void CMyDlg::OnBnClickedOk()
{
CWnd *cWnd = FromHandle(m_hWnd);
CDC *pDC = cWnd->GetDC();
bool top = false;
bool right = false;
int i,j;
for(i=10,j=92;i<=200 && j>10;)
{
pDC->SetPixel(i,j,RGB(255,255,255));
Sleep(10);
if(!top)
j-=1;
else
j+=1;
if(j%4==0)
{
if(!right)
i++; // if reaches right side i--;
else{
i--;
}
}
if(j==12)
top=true;
else if(j==90)
top = false;
if(i == 200)// make right = true if reaches right side
right = true;
else if(i == 10)// make false it reaches left side
right = false;
}
}
I am getting output something like this
NOTE: this will cause infinite loop, you need to check condition where you have to stop printing pixels.
You are NOT looping with Sleep(10) in your WM_PAINT handler, are you?
MFC or not, you should separate your data processing from presentation.
It appears you are trying to do an animation; the simplest way to do it is to have an off-screen (memory) DC and drawing your pixels on it. At certain times (frame rate?), you would call parent's InvalidateRect()/UpdateWindow() pair. Then in ON_PAINT, you would BitBlt() your prepared DC onto your preferred location in the dialog.
In my program what I am drawing gets stuck on to the screen I am drawing on, by this I mean that what I previously drawed onto the screen stays after I call SDL_UpdateWindowSurface(). Here is my code.
void tower_manager::render()
{
m_tower.draw(camx, camy,m_screen);
//SDL_BlitSurface(test, NULL, m_screen, NULL);
SDL_Rect rect = { 32, 32, 32, 32 };
//draw the tower walls;
for (int x = 0; x < towerWidth; x++)
{
for (int y = 0; y < towerHeight * 2; y += 2)
{
rect.x = x*blockSize - camx;
rect.y = y*blockSize - camy;
SDL_BlitSurface(test, NULL, m_screen, &rect);
}
}
SDL_UpdateWindowSurface(m_window);
}
Apparently I need at least 10 reputation to post images so I cant post a screen shot but here is an example, you know what happens to the desktop when a windows application freezes and it keeps drawing the same window over and over again and you can draw it around to make art and stuff? That's exactly what it looks like is happening here. Also I have another issue when I call the tower objects method that is originally going to draw the tower using the same code it does not draw or do anything at all(i am passing in a pointer to the screen I am drawing to in its parameter).
You would want to clear the surface regions that you are drawing to. If you don't, then the screen surface retains the old renderings from previous frames and you are drawing on top of them. This causes a smearing artifact.
An old optimization (no longer so useful with SDL2 or OpenGL) here is to keep track of dirty rectangles and clear each of them, but the simplest way is to just clear the entire surface each frame before rendering.
So, once per frame do something like this:
SDL_FillRect(m_screen, NULL, 0x000000);
I'm making a game in C++ with SDL, and I want to render particles with SDL_FillRect().
I've played with the code for hours, but no matter what I do, the particles are not drawing.
This is the code in my Render function (I made sure that I was in fact calling the function):
void Particle::Render()
{
SDL_Rect rect;
rect.x = x;
rect.y = y;
//rect.w = Particle::Particle_Size;
//rect.h = Particle::Particle_Size;
rect.w = 8;
rect.h = 8;
surface = SDL_CreateRGBSurface(SDL_SWSURFACE,8,8,32,0,0,0,0);
if(SDL_FillRect(surface,&rect,SDL_MapRGB(surface->format,0,0,0)) != 0) printf("Error");
//SDL_RenderCopy(renderer,texture,NULL,&rect);
}
The console isn't printing "Error", so the SDL_FillRect() is successful. However, no rects are being drawn to the screen.
I tried creating a texture with SDL_CreateTextureFromSurface() with that surface passed in, and then used SDL_RenderCopy, which is commented out in the above function, but it worked before I commented it out. I want to use SDL_FillRect so I could have colored textures though.
Am I missing anything?
I think you could use this function to do what you are looking for:
SDL_RenderFillRect()
https://wiki.libsdl.org/SDL_RenderFillRect
You would have to set the renderer color before with:
SDL_SetRenderDrawColor();
I think you could also update the window surface to get what you have to work.
That would use
SDL_UpdateWindowSurface().
https://wiki.libsdl.org/SDL_UpdateWindowSurface?highlight=%28%5CbCategoryVideo%5Cb%29%7C%28CategoryEnum%29%7C%28CategoryStruct%29
Hope it helps!
The SDL_CreateRGBSurface() function creates an off-screen surface. If you want to draw to the screen, you will have to draw to the surface returned by SDL_GetWindowSurface().
That is, if you are using SDL 2.0.
I made a heap on console. I've done all coding. Now I just need to show the heap tree on a drawing board. I am new to MFC and learned some basics like using a pDC pointer to draw nodes. Like pDC->ellipse(int x,int x2,int y,int y2). However I don't get how I will be able to show a complete tree on the board.
void CAst3View::OnDraw(CDC* pDC)
{
CAst3Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(a.control_draw == true)
{
pDC->Ellipse(100, 100 ,500,500);
}
//if (a.height!=0)
//{
// pDC->Ellipse(100, 100 ,500,500);
//}
// TODO: add draw code for native data here
}
This gives me one circle on the drawing board.
The Ellipse function is used to draw a circle. To draw a complete tree, you may need to change the x- and y- coordinates and keep drawing the circle, then connect each circle using the LineTo function.
Related post which may help you: Tree Circle Draw Control