I am using this BitBlt wrapper:
http://www.codeproject.com/Articles/21426/Double-Buffering-in-a-Win-API-Program
I initialize it in main():
biop = new Bitmap_Operations();
biop->Initialize_Buffers(m_hDC, m_hWND, 1);
biop->Create_Buffer(0);
Helper Functions:
void CreateBuffer()
{
biop->Create_Buffer(0);
}
void Render()
{
biop->Copy_to_Screen(0);
}
void ClearBuffer()
{
biop->Free_Buffer(0);
}
void DrawBox(int x, int y, int r, int g, int b, int size, int thickness)
{
// Brush style to hollow
m_LogBrush.lbStyle = BS_NULL;
// Create a logical brush and select into the context
m_hBrush = CreateBrushIndirect(&m_LogBrush);
HBRUSH hbrOldBrush = (HBRUSH)SelectObject(biop->Get_DC_Buffer(0), m_hBrush);
// Create a logical pen and select into the context
m_hPen = CreatePen(PS_SOLID, thickness, RGB(r, g, b));
HPEN hpOldPen = (HPEN)SelectObject(biop->Get_DC_Buffer(0), m_hPen);
// Draw the rectangle
Rectangle(biop->Get_DC_Buffer(0), (x - size / 2), (y - size / 2), (x + size / 2), (y + size / 2));
// Remove the object
SelectObject(biop->Get_DC_Buffer(0), hbrOldBrush); // first you must restore DC to original state
SelectObject(biop->Get_DC_Buffer(0), hpOldPen); // same here
DeleteObject(m_hBrush);
DeleteObject(m_hPen);
}
I spawn a thread to render data:
// Inside a thread
while (1)
{
CreateBuffer();
for (int i = 0; i < 1028; i++)
{
//
DrawBox()
//
}
Render();
ClearBuffer();
}
I am using FindWindow() to render on top of another application. Everything works fine, the boxes get rendered, ect, but there is a crazy full-screen flicker that seems to have a black background. My guess its when I draw from memory to the application?
I am using double buffering to avoid a flicker, but it seems like it made it worse. Any ideas?
Thanks.
I would use UpdateLayeredWindow APIs instead, if you need to draw transparent things on top of existing windows.
Related
I have this function:
void Texture::render(int x, int y, int w, int h, SDL_Renderer *&renderer, double angle, SDL_Point* center, SDL_RendererFlip flip)
{
// Set a destination value to -1 to keep the current value
if (x < 0) { x = rect.x; }
if (y < 0) { y = rect.y; }
if (w < 0) { w = rect.w; }
if (h < 0) { h = rect.h; }
// Create destination rectangle
SDL_Rect dstRect = { x, y, w, h };
// Render to screen
SDL_RenderCopyEx(renderer, texture, &rect, &dstRect, angle, center, flip);
}
It works. It creates an image of the correct size at the location I want. But I want to add a chunk of code where it resizes the texture itself to be the size given in the destRect.
So, anyone who finds this and reads the conversation I had with Nelfeal in the comments will see that I had a misunderstanding of how SDL_RenderCopyEx works. There's no need to resize the texture. If you need to do something like that, you can just use the dstRect when you copy it.
Actually, as far as I can find, there isn't a method to resize the actual texture itself. I'm sure one exists, but it's definitely not something people are commonly using. Which is usually a sign that it's a bad idea.
I've tweaked my code to try and simplify it, for anybody who's trying to do something similar to me:
void render(SDL_Renderer *&renderer, SDL_Rect *dstRect=NULL, SDL_Rect &srcRect=NULL, double angle=0.0, SDL_Point* center=NULL, SDL_RendererFlip flip=SDL_FLIP_NONE);
void Texture::render(SDL_Renderer *&renderer, SDL_Rect *dstRect, SDL_Rect *srcRect, double angle, SDL_Point* center, SDL_RendererFlip flip)
{
// Check to see if a destination was provided
bool check = false;
if (dstRect == NULL)
{
check = true;
dstRect = new SDL_Rect();
dstRect->x = 0;
dstRect->y = 0;
dstRect->w = SCREEN_WIDTH;
dstRect->h = SCREEN_HEIGHT;
}
// Check to see if the entire texture is being copied
if (srcRect == NULL) { srcRect = ▭ }
// Render to screen
SDL_RenderCopyEx(renderer, texture, srcRect, dstRect, angle, center, flip);
// Free dstRect
if (check) delete dstRect;}
And it looks like this when using the function:
bgTex.render(renderer);
blobTex.render(renderer, &blobDstRect);
I'm trying to make smooth animations in the console window in c++. I'm using windows.h for functions like Ellipse, and LineTo. The issue is that the frames are very slow and blink a lot. Sometimes the frames get progressively slower and slower as the program moves along. I tried animating a circle that moves down to the right, and a line that goes from the upper left corner to wherever the circle is. When I used the LineTo function, the line was black. I don't know how to color it. Any help would be appreciated, I just want to be able to draw and animate in the console.
#include <windows.h>
void drawSprt(int x, int y) {
HWND handle = GetConsoleWindow();
HDC dc = GetDC(handle);
int r = 10;
int a;
COLORREF color = 0x00FFFFFF;
Ellipse( dc, x-r,y-r,x+r,y+r);
MoveToEx( dc, 0, 0, NULL);
LineTo( dc, x+r, y+r);
ReleaseDC(handle, dc);
}
int main() {
int x = 100;
int y = 100;
start:
drawSprt(x,y);
Sleep(500);
x+=5;
y+=5;
system("cls");
goto start;
}
I'm currently using 5MP Camera, so I convert BYTE* to GDI+ Bitmap object and uses Graphics object to draw on picture control (all GDI+ objects)
and I want to draw a string on it and when I do so, resolution (quality or whatsoever) gets strange. here're the images.
this is the original image
this is the image with the text on it
And here's my code. it uses MFC's WM_MOUSEMOVE. and when mouse pointer gets on CRect(dispRC[array]), it renders string "aa" on the Bitmap object.
and when I do so, quality of image gets lower or I don't exactly know it changes the IMAGE. (You might not notice because those are captured images, but latter image's quality gets lower.)
void CSmall_StudioDlg::OnMouseMove(UINT nFlags, CPoint point)
{
CPoint insidePoint;
// MAXCAM is the number of bitmap objects.
for (int i = 0; i < MAXCAM; i++)
{
// m_pBitmap[MAXCAM] is array of Bitmap* which contains address of Gdiplus::Bitmap objects.
if (m_pBitmap[i] != NULL)
{
// m_rcDisp[MAXCAM] are CRect objects which has information of picture control.
// i.e. GetDlgItem(IDC_BIN_DISP)->GetWindowRect(m_rcDisp[BINARY_VID]);
if (point.x > m_rcDisp[i].TopLeft().x && point.y > m_rcDisp[i].TopLeft().y)
{
if (point.x < m_rcDisp[i].BottomRight().x && point.y < m_rcDisp[i].BottomRight().y)
{
StringFormat SF;
insidePoint.x = point.x - m_rcDisp[i].TopLeft().x;
insidePoint.y = point.y - m_rcDisp[i].TopLeft().y;
Graphics textG(m_pBitmap[i]);
textG.SetTextRenderingHint(TextRenderingHintSingleBitPerPixel);
Gdiplus::Font F(L"Palatino Linotype Bold", 10, FontStyleBold, UnitPixel);
RectF R(insidePoint.x, insidePoint.y, 20, 100);
SF.SetAlignment(StringAlignmentCenter);
SF.SetLineAlignment(StringAlignmentCenter);
SolidBrush B(Color(0, 0, 0));
textG.DrawString(_T("aa"), -1, &F, R, &SF, &B);
// m_pGraphics[MAXCAM] is made like this
// i.e.
// static CClientDC roiDc(GetDlgItem(IDC_ROI_DISP));
// m_hDC[ROI_VID] = roiDc.GetSafeHdc();
// m_pGraphics[ROI_VID] = Graphics::FromHDC(m_hDC[ROI_VID]);
m_pGraphics[i]->DrawImage(m_pBitmap[i], 0, 0, m_vidwidth[i], m_vidheight[i]);
}
}
}
}
CDialogEx::OnMouseMove(nFlags, point);
}
Hope I get a helpful answer.
Thanks!
I had a similar problem and solved it by creating the GDI+ font from a Windows font like this:
Gdiplus::Font font(hDc, hFont);
where hDc is a DC handle and hFont is a font handle.
Can you try if this helps?
I want to be able to draw all my text, lines , triangles and other stuff to screen and then clear the screen and draw something new, BUT this method makes the screen flicker, and all the drawings dont appear at the same time.
My idea is to draw to some kind of a buffer and then draw that buffer to the screen and clear the buffer, and repeat. This way the screen wont flicker and all will be drawn at the same time.
I am using windows.h , Visual Studio.
#include <Windows.h>
#include <iostream>
using namespace std;
struct vec2d
{
int x, y;
};
void Line(HDC dc, vec2d a, vec2d b)
{
MoveToEx(dc, a.x, a.y, NULL);
LineTo(dc, b.x, b.y);
}
vec2d GetMousePos(HWND console)
{
vec2d out;
POINT p;
GetCursorPos(&p);
out.x = p.x; out.y = p.y;
return out;
}
int main()
{
HWND console = GetConsoleWindow();
HDC dc = GetDC(console);
SelectObject(dc, CreatePen(PS_SOLID, 1, RGB(255, 255, 255)));
while (1)
{
//BitBlt(dc, 0, 0, 1000, 1000, 0, 0, 0, BLACKNESS); Flickering is much much bigger, because its faster
system("cls");
Line(dc, { 0, 0 }, GetMousePos(console));
}
}
Thanks in advance, Mark.
I don't think you have as much control over a console window as you would over your own HWND. I was able to eliminate the flicker in your code by replacing system("cls"); with InvalidateRect().
RECT client;
GetClientRect(console, &client);
while (1)
{
InvalidateRect(console, &client, TRUE);
Line(dc, console, { 0, 0 }, GetMousePos(console));
}
(You can probably improve this by only invalidating the area where the previous line was drawn.)
Also, one other change you can make (unrelated to flicker) is to add:
ScreenToClient(console, &p);
to GetMousePos() after you call GetCursorPos(&p);. This will map the pointer co-ords to the window instead of the screen.
Further reading on creating your own window: Creating a Window. Not as simple as using a console window, but you have much greater control.
I'm having an issue with a program I'm working on. Occasionally, it will just freeze. No errors or anything.
The game is a multiplayer game where you fly a ship around. Pictures of other players and powerups move in and out of view depending on your location. For the most part, it works great, but under certain circumstances, it locks up.
I've tracked it down to when it BLITs one surface onto another. (SDL_BlitSurface).
If I comment out the single line of code where it blits (SDL_BlitSurface), and replace the graphic with a simple circle, it'll never freeze under any circumstances. But, comment out the circle and replace it with blitting the graphic again, and it'll randomly freeze. The frustrating part is, sometimes it will, sometimes it won't. Sometimes the graphic will sit on screen for a few moments and then freeze, sometimes it'll freeze the moment it shows up. Sometimes, it won't freeze at all. I simply cannot track it down to anything in particular.
I have ample amount of code that checks for NULL surfaces and it doesn't seem to stop it.
I also have it set up to output information about all the graphics to a file (such as width, height, location in memory, x, y, etc) and nothing seems out of the ordinary.
My main questions are, what about surfaces can cause SDL_BlitSurface to freeze? And what other checks can I add for surfaces to make sure it doesn't try to blit bad surfaces?
The code is too long to list, but here is how it works:
class Player
{
Player();
int x;
int y;
int xvel;
int yvel;
SDL_Surface *DrawScreen;
SDL_Surface *ShipPic;
void check_player_dist();
void check_powerup_dist();
void update();
};
class PowerUp
{
int x;
int y;
int type;
SDL_Surface *Powerup_Pic;
};
Player::Player()
{
Apply_Surface(0, 0, PlayerShipPics, ShipPic);
}
Player::Update(Player p[], PowerUp pu[])
{
x += xvel;
y += yvel;
for (int i = 0; i < Num_Players; i++)
{
if (check_on_screen(p[i].x, p[i].y) == true)
{
Apply_Surface(x - p[i].x, y - p[i].y, p[i].ShipPic, DrawScreen);
}
}
for (int i = 0; i < Num_PowerUps; i++)
{
if (check_on_screen(pu[i].x, pu[i].y) == true)
{
Apply_Surface(x - pu[i].x, y - pu[i].y, pu[i].Pic, DrawScreen);
}
}
}
int main()
{
SDL_Surface *Screen;
Player players[4];
PowerUp powerups[200];
Num_Players = 4;
Num_PowerUps = 200;
while (quit == false)
{
for (int i = 0; i < Num_Players; i++)
{
players[i].update(players, powerups);
switch (i)
{
case 0: ScreenX = 0; ScreenY = 0; break;
case 1: ScreenX = ScreenWid / 2; ScreenY = 0; break;
case 2: ScreenX = 0; ScreenY = ScreenHigh / 2; break;
case 3: ScreenX = ScreenWid / 2; ScreenY = ScreenHigh / 2; break;
}
Apply_Surface (ScreenX, ScreenY, players[i].DrawScreen, Screen);
}
if (SDL_Flip(Screen) == -1)
{
return -1;
}
}
}
void Apply_Surface (int x, int y, SDL_Surface* Source, SDL_Surface* Destination, SDL_Rect* Clip)
{
SDL_Rect Offset;
Offset.x = x;
Offset.y = y;
if ((Source != NULL) && (Destination != NULL))
{
SDL_BlitSurface (Source, Clip, Destination, &Offset );
}
}
I've noticed it generally freezes when two or more players are near each other and it tries to draw the same power-up on both of their screens. But again...not always!
Well, I figured out what it was.
I was using the SDL_GFX library along with my game. Many of the images were created using rotozoomSurface(), which is a function of SDL_GFX.
Turns out there's a bug in it where, under certain circumstances that I don't know, it'll create a bad surface that will work "most" of the time, but under the right conditions, will crash. Such as, being placed at a particular x & y coordinate on the screen. (Don't know for sure). The rotated/zoomed images would work about 95% of the time, so it was very difficult to pin point what the issue was.
The work around was, when the image was created, just SDL_BlitSurface() it onto another surface under controlled conditions, such as putting it at coordinates (0, 0). Then, delete the rotated and zoomed surface, and just use the new "safe" surface.
Works great after that.
Hopefully this will help anyone who's using SDL_GFX and cannot figure out why their program is crashing.
Example:
Before:
SDL_Surface *original = SDL_CreateRGBSurface(SDL_SWSURFACE, Ship_Width, Ship_Height, Screen_BPP, 0, 0, 0, 0);
Apply_Surface(0, 0, ShipsPic, original, &bounds);
SDL_Surface *finished = rotozoomSurface(original, pic_angle, zoom, SMOOTHING_ON);
SDL_FreeSurface(original);
return finished;
After (fixed):
SDL_Surface *original = SDL_CreateRGBSurface(SDL_SWSURFACE, Ship_Width, Ship_Height, Screen_BPP, 0, 0, 0, 0);
Apply_Surface(0, 0, ShipsPic, original, &bounds);
SDL_Surface *temp = rotozoomSurface(original, pic_angle, zoom, SMOOTHING_ON);
SDL_Surface *finished = SDL_CreateRGBSurface(SDL_SWSURFACE, temp->w, temp->h, Screen_BPP, 0, 0, 0, 0);
Apply_Surface(0, 0, temp, finished);
SDL_FreeSurface(temp);
SDL_FreeSurface(original);
return finished;
And for what it's worth, the Apply_Surface() function:
void Apply_Surface (int x, int y, SDL_Surface* Source, SDL_Surface* Destination, SDL_Rect* Clip)
{
SDL_Rect Offset;
Offset.x = x;
Offset.y = y;
if ((Source != NULL) && (Destination != NULL))
{
SDL_BlitSurface (Source, Clip, Destination, &Offset );
}
}
There's not really enough information to figure out what exactly is going on. Computers don't like to do things "sometimes," they either do them or not, so it leads me to believe that maybe there's some variable that's doing something it shouldn't.
Just in case, what does your Apply_Surface() function look like? I assume that's where you're doing your actual blitting, and if that's where you're having your problems, that would be useful for those of us trying to figure out your dilemma.