Drawing keeps getting stuck to the screen in SDL - c++

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);

Related

glReadPixels doesnt work for the first left click

I am working on a MFC app which is a MDI. One of the child frame uses OpenGL(mixed with fixed function and modern version) called 3d view and another child frame uses GDI called plan view. Both of the views use the same doc.
The 3d view has a function to detect if the mouse cursor is over rendered 3d model by reading pixels and check its depth value.
The function is used for WM_MOUSEMOVE and WM_LBUTTONDOWN events. Most time it works pretty well. But it failed when I move my cursor from the plan view(currently active) to the 3d view and left mouse click. The depth values read from the pixels(called from onLButtonDown) are always all zeros though it is over a model. There is no OpenGL error reported. It only fails on the first mouse click when the 3d view is not activated. Afterwards, everything works well again.
The issue doesn't happen on all machines. And it happens to me but not to another guy with the same hardware machine with me. Is that possible hardware related or a code bug?
Things tried:
I tried to increase the pixel block size much bigger but depths are still all zero.
If I click on the title bar of the 3d view to activate it first, then works.
I tried to set the 3d view active and foreground in the onLButtonDown method before reading pixels. But still failed.(btw, the 3d view should be active already before the OnLButtonDown handler via other message handler fired by the left button down).
I tried to invalidate rect before reading pixels, failed too.
The code is as below:
BOOL CMy3DView::IsOverModel(int x0, int y0, int &xM, int &yM, GLfloat &zWin, int width0 , int height0 )
{
int width = max(1,width0);
int height= max(1,height0);
CRect RectView;
GetClientRect(&RectView);
GLint realy = RectView.Height() - 1 - (GLint)y0 ; /* OpenGL y coordinate position */
std::vector<GLfloat> z(width*height);
//Read the window z co-ordinates the z value of the points in a rectangle of width*height )
xM = max(0, x0-(width-1)/2);
yM = max(0, realy-(height-1)/2);
glReadPixels(xM, yM, (GLsizei)width, (GLsizei)height, GL_DEPTH_COMPONENT, GL_FLOAT, &z[0]); OutputGlError(_T("glReadPixels")) ;
/* check pixels along concentric, nested boxes around the central point */
for (int k=0; k<=(min(height,width)-1)/2; ++k){
for (int i=-k;i<=k;++i){
xM = x0+i;
for (int j=-k;j<=k;++j){
if (abs(i)==k || abs(j)==k) {
yM = realy+j;
zWin=z[(i+(width-1)/2)+width*(j+(height-1)/2)];
if (zWin<1.0-FLT_EPSILON) break;
}
}
if (zWin<1.0-FLT_EPSILON) break;
}
if (zWin<1.0-FLT_EPSILON) break;
}
yM = RectView.Height() - 1 - yM;
if (zWin>1.0-FLT_EPSILON || zWin<FLT_EPSILON) {// z is the depth, between 0 and 1, i.e. between Near and Far plans.
xM=x0; yM=y0;
return FALSE;
}
return TRUE;
}
Just found a solution for that: I called render(GetDC) before any processing in OnLButtonDown. somehow it fixed the issue though I don't think it's necessary.
InvalideRect wont fix the issue since it will update the view for the next WM_PAINT.
Weird, since it works for some machines without the fix. Still curious about the reason.

SDL_FillRect Not Drawing?

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.

SDL and c++ -- More efficient way of leaving a trail behind the player?

so i'm fairly new with SDL, and i'm trying to make a little snowboarding game. When the player is moving down the hill, I want to leave a trail of off-coloured snow behind him. Currently, the way i have this working is I have an array (with 1000 elements) that stores the players last position. Then each frame, I have a for loop that loops 1000 times, to draw out the trail texture in all these last 1000 positions of the player...
I feel this is extremely inefficient, and i'm looking for some better alternatives!
The Code:
void Player::draw()
{
if (posIndex >= 1000)
{
posIndex = 0;
}
for (int i = 0; i < 1000; i++) // Loop through all the 1000 past positions of the player
{
// pastPlayerPos is an array of SDL_Rects that stores the players last 1000 positions
// This line calculates teh location to draw the trail texture
SDL_Rect trailRect = {pastPlayerPos[i].x, pastPlayerPos[i].y, 32, 8};
// This draws the trail texture
SDL_RenderCopy(Renderer, Images[IMAGE_TRAIL], NULL, &trailRect);
}
// This draws the player
SDL_Rect drawRect = {(int)x, (int)y, 32, 32};
SDL_RenderCopy(Renderer, Images[0], NULL, &drawRect);
// This is storing the past position
SDL_Rect tempRect = {x, y, 0, 0};
pastPlayerPos[posIndex] = tempRect;
posIndex++; // This is to cycle through the array to store the new position
This is the result, which is exactly what i'm trying to accomplish, but i'm just looking for a more efficient way. If there isn't one, i will stick with this.
There are multiple solutions. I'll give you two.
1.
Create screen-size surface. Fill it with alpha. On each player move, draw it's current position into this surface - so each movement will add you extra data to this would-be mask. Then blit this surface on screen (beware of blit order). In your case it could be improved by disabling alpha and initially filling surface with white, and blitting it first, before anything else. With that approach you can skip screen clearing after flip, by the way.
I recommend starting with this one.
2.
Not easy one, but may be more efficient (it depends). Save array points where player actually changed movement direction. After it, you need to draw chainline between these points. There is however no builtin functions in SDL to draw lines; maybe there are in SDL_gfx, i never tried it. This approach may be better if you'll use OpenGL backend later on; with SDL (or any other ordinary 2D drawing library), it's not too useful.

Drawing points of handwritten stroke using DrawEllipse (GDI+)

I'm working on an application that draws handwritten strokes. Strokes are internally stored as vectors of points and they can be transformed into std::vector<Gdiplus::Point>. Points are so close to each other, that simple drawing of each point should result into an image of continual stroke.
I'm using Graphics.DrawEllipse (GDI+) method to draw these points. Here's the code:
// prepare bitmap:
Bitmap *bitmap = new Gdiplus::Bitmap(w, h, PixelFormat32bppRGB);
Graphics graphics(bitmap);
// draw the white background:
SolidBrush myBrush(Color::White);
graphics.FillRectangle(&myBrush, 0, 0, w, h);
Pen blackPen(Color::Black);
blackPen.SetWidth(1.4f);
// draw stroke:
std::vector<Gdiplus::Point> stroke = getStroke();
for (UINT i = 0; i < stroke.size(); ++i)
{
// draw point:
graphics.DrawEllipse(&blackPen, stroke[i].X, stroke[i].Y, 2, 2);
}
At the end I just save this bitmap as a PNG image and sometimes the following problem occurs:
When I saw this "hole" in my stroke, I decided to draw my points again, but this time, by using ellipse with width and height set to 1 by using redPen with width set to 0.1f. So right after the code above I added the following code:
Pen redPen(Color::Red);
redPen.SetWidth(0.1f);
for (UINT i = 0; i < stroke.size(); ++i)
{
// draw point:
graphics.DrawEllipse(&redPen, stroke[i].X, stroke[i].Y, 1, 1);
}
And the new stoke I've got looked like this:
When I use Graphics.DrawRectangle instead of DrawEllipse while drawing this new red stroke, it never happens that this stroke (drawn by drawing rectangles) would have different width or holes in it:
I can't think of any possible reason, why drawing circles would result into this weird behaviour. How come that stroke is always continual and never deformed in any way when I use Graphics.DrawRectangle?
Could anyone explain, what's going on here? Am I missing something?
By the way I'm using Windows XP (e.g. in case it's a known bug). Any help will be appreciated.
I've made the wrong assumption that if I use Graphics.DrawEllipse to draw a circle with radius equal to 2px with pen of width about 2px, it will result in a filled circle with diameter about 4-5 px being drawn.
But I've found out that I actually can't rely on the width of the pen while drawing a circle this way. This method is meant only for drawing of border of this shape, thus for drawing filled ellipse it's much better to use Graphics.FillEllipse.
Another quite important fact to consider is that both of mentioned functions take as parameters coordinates that specify "upper-left corner of the rectangle that specifies the boundaries of the ellipse", so I should subtract half of the radius from both coordinates to make sure the original coordinates specify the middle of this circle.
Here's the new code:
// draw the white background:
SolidBrush whiteBrush(Color::White);
graphics.FillRectangle(&whiteBrush, 0, 0, w, h);
// draw stroke:
Pen blackBrush(Color::Black);
std::vector<Gdiplus::Point> stroke = getStroke();
for (UINT i = 0; i < stroke.size(); ++i)
graphics.FillEllipse(&blackBrush, stroke[i].X - 2, stroke[i].Y - 2, 4, 4);
// draw original points:
Pen redBrush(Color::Red);
std::vector<Gdiplus::Point> origStroke = getOriginalStroke();
for (UINT i = 0; i < origStroke.size(); ++i)
graphics.FillRectangle(&redBrush, origStroke[i].X, origStroke[i].Y, 1, 1);
which yields following result:
So in case someone will face the same problem as I did, the solution is:

DirectX problems

I have a couple of queries regarding programming in DirectX using C++.
The first problem that I am having is that I have a texture that doesn't display on screen properly. The window is set to 800x600 when it is created and the texture is also 800x600 but when the program is loaded, only part of the texture is displayed. The code is shown below for the texture loading and drawing.
//This sets the image
helpFileTexture = new Texture(d3dDevice, L"../Resources/Help Guide.png");
//This is the draw function
helpFileTexture->Draw(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
//Which calls this
void Texture::Draw(long xPos, long yPos, long width, long height)
{
sprite->Begin(NULL);
RECT imageRectangle;
imageRectangle.left = xPos;
imageRectangle.top = yPos;
imageRectangle.right = imageRectangle.left + width;
imageRectangle.bottom = imageRectangle.top + height;
sprite->Draw(texture, &imageRectangle, &D3DXVECTOR3(1.0f, 1.0f, 0.0f), &D3DXVECTOR3((float)xPos, (float)yPos, 0.0f), D3DCOLOR_XRGB(255, 255, 255));
sprite->End();
}
As I said the SCREEN_WIDTH is set to 800 and the SCREEN_HEIGHT is set to 600 (which are also the same dimensions as the image). It draws from the top left as it should do but will only show part of the image. The window size was set to about 1100x1100 when the entire image could be seen. Have I done something wrong in the coding to set the image size.
The next thing is that I am having a problem hiding the cursor. I want to hide the cursor when I click the left mouse button and then have it reappear when I let go. But the cursor does not disappear. The coding for this is below.
if(input->mouseButtons.rgbButtons[0])
{
d3dDevice->ShowCursor(FALSE);
GetCursorPos(&input->mousePosition);
SetCursorPos(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
input->mousePosition.x -= SCREEN_WIDTH / 2;
mainCamera->UpdateYaw(input->mousePosition.x * rotationSpeed);
indexYaw += mainCamera->GetYaw();
D3DXMatrixRotationY(&viewMatrix, indexYaw);
d3dDevice->SetTransform(D3DTS_VIEW, &viewMatrix);
}
else
{
d3dDevice->ShowCursor(TRUE);
}
As you can see the cursor is suppose to disappear when the left mouse button is click for the camera control but it still shows.
The last couple of things is what is the best way to implement collision detection between objects and terrain following or can you link me to where a good place to find these would be.
I know this is a lot I have asked but any help would be great
The fix you implemented is not correct (the scaling one). The reason for the sizing issue is that when the texture is loaded using the D3DXLoadTextureFromFile method, DirectX changes the size of the image to the nearest power of 2 higher than the actual size. Hence the reason for it appearing larger than the screen.
So, in order to prevent it from doing this, you should use the D3DXLoadTextureFromFileEx method, and specify D3DX_DEFAULT_NONPOW2 for parameters 3 and 4. This will stop DirectX from scaling up the size of the texture. For more information on the method, refer to the MSDN page: http://msdn.microsoft.com/en-us/library/bb172802(v=vs.85).aspx
Note: Be sure to use D3DPOOL_MANAGED as the D3DPOOL option, otherwise if you use D3DPOOL_DEFAULT your models will become see through! (as I found out).