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;
}
Related
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 have the following code:
POINT p;
int main(void) {
HDC hdc = GetDC(NULL);
while(!GetAsyncKeyState(VK_F1)) {
GetCursorPos(&p);
SetPixel(hdc, p.x, p.y, RGB(73, 214, 0));
}
DeleteObject(hdc);
}
What I want to achive is when I move mouse the pixel at curent cursor position changes its color until the program is stopped. However I see a few issues here:
The pixel is drawn below cursor position (resolution?) and after some time all pixels changes to default color. How Can I resolve the problem? Thanks for any help.
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.
Using OpenCV 2.4.3, I am trying to draw a circle on top of an image centered on the mouse (x,y) position when the user is moving the mouse, and just that circle should be there once the mouse stops moving (only the original image with just one circle drawn should be shown in that moment). I thought it was going to be easy, however, I´ve been researching and trying for a couple of hours and can´t make it work the way I described.
Im attaching my code underneath. If anyone could help out I´d be really grateful.
void my_mouse_callback( int event, int x, int y, int flags, void* param );
bool moving_mouse = false;
int main()
{
const char* name = "Circle Example";
IplImage* image_circle = cvLoadImage( "../data/lena.png" );
IplImage* image = cvLoadImage( "../data/lena.png" );
namedWindow(name, CV_WINDOW_AUTOSIZE );
// Set up the callback
cvSetMouseCallback( name, my_mouse_callback, (void*) image_circle);
//Main Loop
while(cvWaitKey(15) != 27){
//If mouse is moving draw circle on top of image
if(moving_mouse){
cvShowImage(name, image_circle);
moving_mouse = false;
}
//If mouse stops moving draw original image and reset image_cicle
else{
cvShowImage(name, image);
image_circle = cvCloneImage(image);
}
}
cvReleaseImage(&image_circle);
cvReleaseImage(&image);
cvDestroyWindow(name);
return 0;
}
// Mouse callback
void my_mouse_callback( int event, int x, int y, int flags, void* param ){
switch( event ){
case CV_EVENT_MOUSEMOVE:
//Drawing a Circle
cvCircle(param,cvPoint(x,y),25,CV_RGB(0,255,0),1);
moving_mouse = true;
break;
}
}
I show you one approach to do this. I explain it later and tell you a difficulty you will have:
static int mouse_x = -1;
static int mouse_y = -1;
void my_mouse_callback( int event, int x, int y, int flags, void* param )
{
if(event == CV_EVENT_MOUSEMOVE)
{
mouse_x = x;
mouse_y = y;
}
}
int main()
{
IplImage* image;
IplImage* image_circle = NULL;
... // load image, create window, initiate callback, etc
int x = -1;
int y = -1;
while(cvWaitKey(15) != 27)
{
if(x != mouse_x || y != mouse_y)
{
x = mouse_x;
y = mouse_y;
cvReleaseImage(&image_circle);
image_circle = cvCloneImage(image);
cvCircle(image_circle,cvPoint(x,y),25,CV_RGB(0,255,0),1);
cvShowImage(name, image_circle);
}
}
... // destroy image
}
Explanation
Here, in the mouse event, you just store the coordinates of the mouse pointer. When an event takes place, the main program will check if the mouse moved to redraw the full image again. Since you want to erase the previous circle, you must copy the original image first to draw the new circle later. You could make this smarter by just copying the part of the original image that were the previous circle was, instead of the entire image.
Problem
A problem when doing something like this in OpenCV is that you can't detect when the mouse goes out of your window, so that you will always have a circle drawn in your image. I don't think you can solve this just with OpenCV, since I don't think there is a kind of MOUSE_OUT event. You would need to look for some Qt callback or system function.
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.