I have a problem about make some circle orbit (solar system stimulation) in C.
Actually, I did it about a day. but I can't figure it out.
First, how to change the planets movement speed?
Some friends told me that I can use "If" for speed arrange, but I failed....
Second, Location setting. I draw some circle with ellipse but I don't know how to make orbit.
my earth orbit goes wrong... there are some codes that I made.
#include <Windows.h>
#include <stdio.h>
#include <math.h>
#define solar_size 30
#define earth_size 16
#define PI 3.141592654
#define MOVE_SPEED 3
#define rad angle*180/PI
int angle;
double sun_x,sun_y,earth_x,earth_y;
double x,y;
int dx;
int dy;
int i;
int main(void) {
HWND hwnd = GetForegroundWindow();
HDC hdc = GetWindowDC(hwnd);
SelectObject(hdc, CreateSolidBrush(RGB(0, 0, 0)));
Rectangle(hdc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
TextOut(hdc, 250, 450, L"solar system Simulation", 23);
while (1) {
sun_x = 250;
sun_y = 250;
earth_x = sun_x + 40;
earth_y = sun_y + 40;
SelectObject(hdc, CreatePen(PS_SOLID, 3, RGB(255, 0, 0)));
SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0)));
Ellipse(hdc, sun_x, sun_y, sun_x + solar_size, sun_y + solar_size);
for (angle = 0; angle <= 360; angle++) {
SelectObject(hdc, CreatePen(PS_SOLID, 3, RGB(0, 0, 220)));
SelectObject(hdc, CreateSolidBrush(RGB(0, 0, 220)));
Ellipse(hdc, earth_x, earth_y, earth_x + earth_size, earth_y + earth_size);
Sleep(50);
SelectObject(hdc, CreatePen(PS_SOLID, 3, RGB(0, 0, 0)));
SelectObject(hdc, CreateSolidBrush(RGB(0, 0, 0)));
Ellipse(hdc, earth_x + 30, earth_y + 30, earth_x + earth_size, earth_y + earth_size);
earth_x = 40 * cos(rad)+40;
earth_y = 40 * sin(rad)+40;
}
continue;
}
}
Your code suffers from being unorganized. For example, you mix the variables like earth_size and hard-wired numbers like 16 freely. That's a recipe for disaster. Please try to be more systematic.
It's hard not to make an answer a laundry list of errors.
The position (px, py) on a circle with centre (cx, cy) and radius r is:
px = cx + r * cos(angle)
py = cy + r * sin(angle)
Therefore, your initialization is wrong:
earth_x = sun_x + 40;
earth_y = sun_y + 40; // should be just sun_y
The way the Ellipse function in GDI works, your drawing command should look like:
Ellipse(hdc, earth_x - earth_size / 2, earth_y - earth_size / 2,
earth_x + earth_size / 2, earth_y + earth_size / 2);
Perhaps it is useful to collect the data of the celestial bodies (position, size, colour) in a struct and write a drawing function for it that just says DrawBody(hdc, earth), so that you don't have to repeat (viz copy and paste) the drawing code.
As for your speed: One possible source of error is here:
#define rad angle*180/PI
That's the wrong way round.
Finally, learn how SelectObject works: You should save the return value in a variable and select it back to the DC after you are done. If you don't do that, you will leak GDI objects. You can see how many GDI objects your application uses in the Task Manager. If that number grows constantly, you are leaking objects. Eventually, your application will behave strangely.
Related
I am going to create some kind of "remote desktop" application that streams the content of the screen over a socket to a connected client.
In order to take a screenshot, I've come up with the following piece of code, which is a modified version of examples I've seen here and there.
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
int _tmain( int argc, _TCHAR * argv[] )
{
int ScreenX = 0;
int ScreenY = 0;
BYTE* ScreenData = 0;
HDC hScreen = GetDC(GetDesktopWindow());
ScreenX = GetDeviceCaps(hScreen, HORZRES);
ScreenY = GetDeviceCaps(hScreen, VERTRES);
ScreenData = (BYTE*)calloc(4 * ScreenX * ScreenY, sizeof(BYTE) );
BITMAPINFOHEADER bmi = {0};
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biPlanes = 1;
bmi.biBitCount = 32;
bmi.biWidth = ScreenX;
bmi.biHeight = -ScreenY;
bmi.biCompression = BI_RGB;
bmi.biSizeImage = 0; // 3 * ScreenX * ScreenY;
int iBegTc = ::GetTickCount();
// Take 100 screen captures for a more accurante measurement of the duration.
for( int i = 0; i < 100; ++i )
{
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, ScreenX, ScreenY);
HDC hdcMem = CreateCompatibleDC (hScreen);
HGDIOBJ hOld = SelectObject(hdcMem, hBitmap);
BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hScreen, 0, 0, SRCCOPY);
SelectObject(hdcMem, hOld);
GetDIBits(hdcMem, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
DeleteDC(hdcMem);
DeleteObject(hBitmap);
}
int iEndTc = ::GetTickCount();
printf( "%d ms", (iEndTc - iBegTc) / 100 );
system("PAUSE");
ReleaseDC(GetDesktopWindow(),hScreen);
return 0;
}
My problem is that the code within the loop takes too long too execute. In my case it's about 36 ms per iteration.
I am wondering if there are statements that could be done just once and thus put outside of the loop, likI did for the byte buffer. I don't know however which are the ones that I must do for each new image, and which are the ones I can only do one time.
Keep BitBlt and GetDIBits inside the loop, move the rest outside the loop as follows:
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, ScreenX, ScreenY);
HDC hdcMem = CreateCompatibleDC (hScreen);
HGDIOBJ hOld = SelectObject(hdcMem, hBitmap);
for( int i = 0; i < 100; ++i )
{
BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hScreen, 0, 0, SRCCOPY);
//hBitmap is updated now
GetDIBits(hdcMem, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
//wait...
}
SelectObject(hdcMem, hOld);
DeleteDC(hdcMem);
DeleteObject(hBitmap);
In addition bmi.biSizeImage should be set to data size, in this case 4 * ScreenX * ScreenY
This won't make the code noticeably faster. The bottle neck is at BitBlt. It's still about 30 frames/sec, this should be okay unless there is a game or movie on the screen.
You might also try saving to a 24 bit bitmap. It won't make any difference in this code but data size would be smaller ((width * bitcount + 31) / 32) * 4 * height)
The Aero feature of Windows seems to affect the BitBlt speed.
If you iteratively BitBlt even one pixel from the display, it will run at about 30 frames per second, and the CPU usage will be near idle. But if you turn off the Aero feature of Windows, you'll get BitBlt speeds that are remarkably faster.
I'm trying to make a projectile shoot using with allegro library in C.And I couldn't do it in no way.My all code is below.My circle goes up but then disappear.Even if not I can't bring it down to the ground.I'm not good at physic so if my equals are wrong please forgive me.
#include <allegro.h>
#include < math.h >
void StartAlleg(); // my start program function
void EndAlleg();
int main() {
StartAlleg();
BITMAP *buffer = create_bitmap(640, 480);
int g = 10, Vo = 0 , Vx = 5, Vy = 475, angle= 0;
double time = 0, tUp = 0,hmax=0; //g is gravity
show_mouse(screen);
while (!key[KEY_ESC])
{
circle(buffer, Vx, Vy, 5, makecol(255, 0, 0));
if (key[KEY_UP]&&angle<360) angle++;
if (key[KEY_RIGHT]) Vo++;
if (key[KEY_DOWN] && angle>0) angle--;
if (key[KEY_LEFT] && Vo>0) Vo--;
textout_ex(buffer, font, "Player 1 : ", 0, 0, makecol(255, 255, 13), -1);
textprintf(buffer, font, 0, 25, makecol(255, 255, 13), "Angle = %d ",angle);
textprintf(buffer, font, 0, 15, makecol(255, 255, 13), "Speed = %d ", Vo);
if (key[KEY_Z] ){
Vx = Vo*cos(double(angle));
Vy = Vo*sin(double(angle));
if (angle== 180 || angle == 360) Vy = 0;
if (angle== 90 || angle== 270) Vx = 0;
if (Vx < 0) Vx *= (-1);
if (Vy < 0) Vy *= (-1);
tUp = Vy / g;
time = tUp * 2;
hmax = (Vy*Vy) / (2*g);
}
textprintf(buffer, font, 0, 35, makecol(255, 255, 13), "tUp Value = %.2f ", tUp);
for (int i = 1; i <= time; i++)
{
if (i<tUp){ Vx = Vx + g; Vy += g; }
else{ Vy -= g; Vx = Vx + g; }
}
blit(buffer, screen, 0, 0, 0, 0, 640, 480);
rest(60);
clear_bitmap(buffer);
}
EndAlleg(); // my end program function
return 0;
}
END_OF_MAIN()
void StartAlleg() {
int depth, res;
allegro_init();
depth = desktop_color_depth();
if (depth == 0) depth = 32;
set_color_depth(depth);
res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
if (res != 0) {
allegro_message(allegro_error);
exit(-1);
}
install_timer();
install_keyboard();
install_mouse();
install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, "A");
}
void EndAlleg() {
clear_keybuf();
}
I think , the main problem is here :
for (int i = 1; i <= time; i++)
{
if (i<tUp){ Vx = Vx + g; Vy += g; }
else{ Vy -= g; Vx = Vx + g; }
}
I didn't try to understand all your code, but it seems that your calculations are wrong.
Here is how gravity can be implemented :
First, you need to keep track of your projectile position, with variables like Px Py. This position will give you the drawing coordinates.
Then you need to keep track of its speed, usually horizontal and vertical speed, with variables like Vx Vy. If your initial speed is a single vector with angle, convert it once.
Every tick of your game (every loop iteration in your case), you add the speeds to the positions. Then to add gravity, you subtract 10 to the vertical speed, also at every tick (it implements acceleration of -10).
And thats all. Negative speeds and accelerations are normal, you don't need to check, but you can check for borders for positions. Also, you should note that you usually divide the speeds and accelerations by the frequency of your ticks, or else the faster your loop the faster the projectile will move.
You should note that this isn't the best way to implement gravity, because this only approximate physics (more ticks per second will give you more accurate simulation). You should google "game implement gravity properly" for an accurate algorithm, I'm not an expert.
I'm using VisualStudio 2010, coding in C++/CLI, and doing all the graphics by GDI. I have a little app that plot continuously a Gaussian curve with some noise added. Every point is added real-time just like I pointed in this post.
Now, my task is to create a little colored area that I can shrink and increase to select a portion of the plot and do some math.
This kind of task is managed by a MouseMove event just like that:
System::Void Form1::pictureBox1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {
//Recalculate the position of the area,
//clean up the old one and redraw a new.
}
It works actually but I'm experiencing a bit graphic "bug".
As you can see, while I'm moving the area, everything under it is been deleted. The grid is here simply because it is static and I'm refreshing it everytime the green area is redrawn.
Actually it is not a bug, for sure it must go like that. To me, it is kinda obvious. I called it like that because it is not what I'm expecting.
I'm asking if there is a way to the green area as if it is upon a different layer. In this way, I would be able to move the green area while the plot is running without being erased.
I tried handling 2 HDC variables and plot the graph and the grid on the first one and the green area on the second one, but it seems not working.
Do you have some nice idea to get through this bad ( to me ) behaviour - maybe with some multilayer thing or some other fancy solutions - or should I give up and waiting for replotting?
Thanks everyone will give me an answer! :)
EDIT:
Here is how I draw my dataseries:
for(int i = 1; i<=1000; i++ ) {
Gauss[i] = safe_cast<float>(Math::Round( a*s*Math::Exp(-Math::Pow(((0.01*1*(i))-portante), 2)/b), 2));
Rumore[i] = safe_cast<float>(Math::Round(r*generatore->NextDouble(), 2));
SelectObject(hdcPictureBox, LinePen);
MoveToEx(hdcPictureBox, i-1+50, 500-convY*(Gauss[i-1]+Rumore[i-1])+50, NULL);
LineTo(hdcPictureBox, i+50, 500-convY*(Gauss[i]+Rumore[i])+50);
e1 = (i+k)%1000; //Buffer
if(i>DXX-54 && i<SXX-54) {
//ErasePen1 = CreatePen(PS_SOLID, 1, RGB(216,191,216));
label1->Text = Convert::ToString(i);
label1->Refresh();
SelectObject(hdcPictureBox, ErasePen1);
}
else {
SelectObject(hdcPictureBox, ErasePen);
}
//HPEN ErasePen1 = CreatePen(PS_SOLID, 1, RGB(216,191,216));
MoveToEx(hdcPictureBox, e1+50, 500-convY*(Gauss[e1]+Rumore[e1])+50, NULL);
LineTo(hdcPictureBox, e1+1+50, 500-convY*(Gauss[e1+1]+Rumore[e1+1])+50);
}
where DXX and SXX are the X-coordinates of areas - DXX starting, SXX ending.
This is how I'm handling the MouseMove. Do_Chan and Do_Clean are essentially the same thing. Do_Clean draws a bigger area with the background color to erase the old area and allowing Do_Chan to draw a new one.
System::Void Form1::pictureBox1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {
if(e->Button == System::Windows::Forms::MouseButtons::Left) {
double span100 = (SXX-DXX)*85/100;
if (e->X > DXX+((SXX-DXX)/2)-15 && e->X < DXX+((SXX-DXX)/2)+15 && (e->Y >30 && e->Y <50)
|| e->X >DXX+((SXX-DXX)/2)-span100/2 && e->X < DXX+((SXX-DXX)/2)+span100/2 && (e->Y >50 && e->Y <550)) {
HBRUSH brush = CreateSolidBrush(RGB(245,255,250));
Do_Clean(hdcPictureBox, DXX, SXX, brush);
double spawn = SXX-DXX;
DXX = e->X - spawn/2;
SXX = e->X + spawn/2;
if(DXX < 50) {
DXX = 51;
}
if(SXX >1050 ) {
SXX = 1049;
}
spawn = SXX - DXX;
CXX = DXX + spawn/2;
HBRUSH brush1 = CreateSolidBrush(RGB(166,251,178));
Do_Chan(hdcPictureBox2, DXX, SXX, brush1);
int k = 4;
int e1 = 0;
for(int i = 1; i<=1000; i++) {
SelectObject(hdcPictureBox, LinePen);
MoveToEx(hdcPictureBox, i-1+50, 500-250*(Gauss[i-1]+Rumore[i-1])+50, NULL);
LineTo(hdcPictureBox, i+50, 500-250*(Gauss[i]+Rumore[i])+50);
e1 = (i+k)%1000; //Buffer
if(i>DXX-54 && i<SXX-54) {
//ErasePen1 = CreatePen(PS_SOLID, 1, RGB(216,191,216));
SelectObject(hdcPictureBox, ErasePen1);
}
else {
SelectObject(hdcPictureBox, ErasePen);
}
//HPEN ErasePen1 = CreatePen(PS_SOLID, 1, RGB(216,191,216));
MoveToEx(hdcPictureBox, e1+50, 500-250*(Gauss[e1]+Rumore[e1])+50, NULL);
LineTo(hdcPictureBox, e1+1+50, 500-250*(Gauss[e1+1]+Rumore[e1+1])+50);
}
}
}
}
As you can see, after I drew the new area, I redraw all the point of the array Gauss+Rumore.
This is how Do_Chan ( Do_Clean is the same ) works:
void Do_Chan(HDC hdc, int dx, int sx, HBRUSH brush) {
//i = 250, y = 50
int y = 50;
int spawn = sx - dx;
HPEN pen = CreatePen(PS_SOLID, 1, RGB(245, 255, 250));
HPEN penC = CreatePen(PS_DOT, 1, RGB(0, 0, 0));
/*Fai il rettangolo */
SelectObject(hdc, pen);
SelectObject(hdc, brush);
POINT punti[4];
punti[0].x = dx;
punti[0].y = y;
punti[1].x = dx +spawn;
punti[1].y = y;
punti[2].x = dx + spawn;
punti[2].y = y+500;
punti[3].x = dx;
punti[3].y = y+500;
Polygon(hdc, punti, 4);
Ellipse(hdc, dx-10, y-20, dx+10, y);
SelectObject(hdc, penC);
MoveToEx(hdc, dx+spawn/2, 50,NULL);
LineTo(hdc, dx+spawn/2, 550);
SelectObject(hdc, pen);
SelectObject(hdc, brush);
Ellipse(hdc, dx-10+spawn/2, y-20, dx+10+spawn/2, y);
SelectObject(hdc, pen);
SelectObject(hdc, brush);
Ellipse(hdc, dx-10+spawn, y-20, dx+10+spawn, y);
//Plot the axis and the grid
}
I have thought of a possible way to do it and every solution had a drawback. For example
creating a thread. It has a drawback of drawing to picturebox dc from a different thread than the one handling the message queue. Not recomended
Another one:
using a timer and for every tick(lets say 16msec) draw. The DXX and SXX will be global variables. In picturebox move event you will only calculate these values(no drawing), also use some critical sections to protect them, and do all the drawing inside tick of timer. This works but you probable encounter some delay if your movement in picturebox is faster than 60fps.
The solution that i came finally was:
Inside your infinite loop:
get the mouse position and state(down or up). In this way you know if the user is dragging the green area and calculate DXX and SXX.
draw three rectangles with FillRect(): from 0 to DXX with picturebox back color, from DXX to SXX with green color and from SXX to the end with picturebox back color to an in memory dc eg hdcMemBackground
draw the grid lines to hdcMemBackground
Use the Point array and the polyline method i told you and in every loop move all your 999 points in the array one place to the left and add one point in the end of the array. To achieve this fill the array once before the infinite loop and inside it do the previous method
BitBlt hdcMemBackground to picturebox dc
Application::DoEvents();
EDIT (some code)
Create your resources once, when form loads, and release them in the end. Your Do_Chan()
creates considerable memory leaks. At form load:
HPEN hLinePenRed = NULL, hLinePenBlack = NULL, hLinePenWhite = NULL, hLinePenBlackDotted = NULL hPenOld; //Global
HBRUSH hBrushGreen = NULL, hBrushWhite = NULL, hBrushOld = NULL; //Global
HBITMAP hBitmap = NULL, hBitmapOld = NULL; //Global
HDC hdcMemBackground = NULL, hdcPicBox = NULL; //Global
//in form load event:
hLinePenRed = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
hLinePenBlack = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
hLinePenWhite = CreatePen(PS_SOLID, 1, RGB(245, 255, 250));
hLinePenBlackDotted = CreatePen(PS_DOT, 1, RGB(0, 0, 0));
hPenOld = SelectObject(hdcMemBackground, hLinePenRed);
hBrushGreen = CreateSolidBrush(RGB(166, 251, 178));
hBrushWhite = CreateSolidBrush(RGB(245, 255, 250));
hBrushOld = SelectObject(hdcMemBackground, hBrushGreen);
HDC hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
hdcPicBox = GetWindowDC(hwndPicBox);
hdcMemBackground= CreateCompatibleDC(hdc);
hBitmap = CreateCompatibleBitmap(hdc, 1050, 550);
hBitmapOld = SelectObject(hdcMemBackground, hBitmap);
DeleteDC(hdc);
In the end when form closes:
SelectObject(hdcMemBackground, hPenOld);
DeleteObject(hLinePenRed);
DeleteObject(hLinePenBlack);
DeleteObject(hLinePenBlackDotted);
DeleteObject(hLinePenWhite);
SelectObject(hdcMemBackground, hBitmapOld);
DeleteObject(hBitmap);
SelectObject(hdcMemBackground, hBrushOld);
DeleteObject(hBrushGreen);
DeleteObject(hBrushWhite);
DeleteDC(hdcMemBackground);
ReleaseDC(hwndPicBox, hdcPicBox);
How to use FillRect and draw ellipses:
RECT rt;
rt.left = 0; rt.top = 0; rt.right = 1050; rt.bottom = 550;
FillRect(hdcMemBackground, &rt, hBrushWhite);
rt.left = DXX; rt.top = 50; rt.right = SXX; rt.bottom = 550;
FillRect(hdcMemBackground, &rt, hBrushGreen);
SelectObject(hdcMemBackground, hBrushGreen);
SelectObject(hdcMemBackground, hLinePenWhite);
Ellipse(hdcMemBackground, dx-10, y-20, dx+10, y);
Ellipse(hdcMemBackground, dx-10+spawn/2, y-20, dx+10+spawn/2, y);
Ellipse(hdcMemBackground, dx-10+spawn, y-20, dx+10+spawn, y);
//Plot the axis and the grid first and then draw the dotted vertical line
SelectObject(hdcMemBackground, hLinePenBlackDotted);
MoveToEx(hdcMemBackground, dx+spawn/2, 50, NULL);
LineTo(hdcMemBackground, dx+spawn/2, 550);
How to find mouse position and mouse state. This code will be at the beginning of each
iteration to see if user dragged the green area and calculate the new DXX, SXX:
/* It is buggy. My mistake
POINT pt;
GetCursorPos(&pt);
ScreenToClient(hwndPicBox, &pt);
if( pt.x >= 0 && pt.x <= picBoxWidth && pt.y >= 0 && pt.y <= picBoxHeight && (GetAsyncKeyState(VK_LBUTTON) & 0x8000) ){ //the mouse is down and inside picturebox
//do your staff
}
*/
Use instead picturebox mouse down, mouse up and mouse move events:
int isScrollingLeft = false; //global, the left circle
int isScrollingRight = false; //global, the right circle
int isScrollingMiddle = false; //global, the middle circle
System::Void Form1::pictureBox1_MouseDown(....){
//check if e.X and e.Y is inside in one of the three circles and set the
//appropriate isScrolling to true
}
System::Void Form1::pictureBox1_MouseMove(....){
if(isScrollingLeft){
//calculate DXX
}
else if(isScrollingRight){
//calculate SXX
}
else if(isScrollingMiddle){ //if you dont scroll this you dont need it
//
}
else{;} //do nothing
}
System::Void Form1::pictureBox1_MouseUp(....){
isScrollingLeft = false;
isScrollingRight = false;
isScrollingMiddle = false; //if you dont scroll this you dont need it
}
The way to move the points one place to the left:
POINT arrayPnt[1000]; //the array of points to be drawn by Polyline()
//the movement
memmove(&arrayPnt[0], &arrayPnt[1], 999 * sizeof(POINT));
//set the last one
arrayPnt[999].x = X;
arrayPnt[999].y = Y;
//Draw the lines
Polyline(hdcMemBackground, &arrayPnt, 1000);
To draw the number i into the label:
HDC hdcLabel1 = NULL; //global
HFONT hFont = NULL, hFontOld = NULL; //global
RECT rtLabel = NULL; //global
char strLabel1[5]; //global
Initialize once at the beggining like everything else
hdcLabel1 = GetWindowDC(label1Hwnd);
SetBkColor(hdcLabel1, RGB(?, ?, ?)); //i believe you use the color of your form
SetTextColor(hdcLabel1, RGB(255, 255, 255));
hFont = CreateFont(21, 0, 0, 0, /* Bold or normal*/FW_NORMAL, /*italic*/0, /*underline*/0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, TEXT("Arial")); //21 is i believe the 16 size in word
hFontOld = SelectObject(hdcLabel1, hFont);
rtLabel.top = 0; rtLabel.left = 0;
rtLabel.right = label1.Width; rtLabel.bottom = label1.Height;
and in the for loop draw the string into the label1
sprintf(strLabel1, "%d", i); //it is toooo slow. I have to think something better
DrawTextEx(hdcLabel1, strLabel1, -1, &rtLabel, DT_VCENTER | DT_SINGLELINE | DT_LEFT, NULL);
In the end ofcource release resources
SelectObject(hdcLabel1, hFontOld);
DeleteObject(hFont);
hFont = NULL;
ReleaseDC(label1Hwnd, hdcLabel1);
If you have any problems do comment.
valter
I am trying to use SDL 2.0 function SDL_RenderDrawPoints() to plot data points on the screen.
In "processing.org", I can use strokeWeight() to change the size of my "points". How to do this in SDL 2.0
SDL does not support it natively,use the SDL_gfx library.
There's a function thicklineRGBA which allows you to specify line width.
int thickLineRGBA (SDL_Renderer *rd, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 width, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
SDL_RenderSetScale
int SDL_RenderSetScale(SDL_Renderer* renderer,
float scaleX,
float scaleY)
Note
The drawing coordinates are scaled by the x/y scaling factors before they are used by the renderer. This allows resolution independent drawing with a single coordinate system.
If this results in scaling or subpixel drawing by the rendering backend, it will be handled using the appropriate quality hints. For best results use integer scaling factors.
Taken from the SDL Wiki
Examlple
#include <SDL2/SDL.h>
#include <iostream>
int main()
{
SDL_Renderer* renderer;
SDL_Window* window;
SDL_Point points[4];
SDL_Point startingPoint;
startingPoint.x = 50;
startingPoint.y = 50;
float scale = 1.0;
if ( SDL_Init( SDL_INIT_EVERYTHING ) != 0 )
std::cout << "Failed to init SDL : " << SDL_GetError();
window = SDL_CreateWindow( "Client", 50, 50, 500, 500, 0 );
if ( window == nullptr )
std::cout << "Failed to apply video mode : " << SDL_GetError();
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED );
if ( renderer == nullptr )
std::cout << "Could not create renderer!";
SDL_RenderSetLogicalSize( renderer, 500, 500 );
// Clear background
SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255 );
SDL_RenderClear( renderer );
SDL_SetRenderDrawColor( renderer, 255, 255, 255, 255 );
// Create first 4 points
points[0].x = startingPoint.x;
points[0].y = startingPoint.y;
points[1].x = startingPoint.x + 50;
points[1].y = startingPoint.y;
points[2].x = startingPoint.x;
points[2].y = startingPoint.y + 50;
points[3].x = startingPoint.x + 50;
points[3].y = startingPoint.y + 50;
SDL_RenderDrawPoints( renderer, points, 4 );
// Create seconds 4 points
startingPoint.x = 125;
scale = 2.0;
points[0].x = startingPoint.x;
points[0].y = startingPoint.y;
points[1].x = startingPoint.x + 50;
points[1].y = startingPoint.y;
points[2].x = startingPoint.x;
points[2].y = startingPoint.y + 50;
points[3].x = startingPoint.x + 50;
points[3].y = startingPoint.y + 50;
// Apply scale
for ( int i = 0; i < 4 ; ++i )
{
points[i].x /= scale;
points[i].y /= scale;
}
SDL_RenderSetScale( renderer, scale, scale );
SDL_RenderDrawPoints( renderer, points, 4 );
// Create third 4 points
startingPoint.x = 200;
scale = 3.0;
points[0].x = startingPoint.x;
points[0].y = startingPoint.y;
points[1].x = startingPoint.x + 50;
points[1].y = startingPoint.y;
points[2].x = startingPoint.x;
points[2].y = startingPoint.y + 50;
points[3].x = startingPoint.x + 50;
points[3].y = startingPoint.y + 50;
// Apply scale
for ( int i = 0; i < 4 ; ++i )
{
points[i].x /= scale;
points[i].y /= scale;
}
SDL_RenderSetScale( renderer, scale, scale );
SDL_RenderDrawPoints( renderer, points, 4 );
SDL_RenderPresent( renderer );
std::cin.ignore();
}
This example will draw three series of four points in a square pattern :
1.0 scale at 50, 50 to 100, 100
2.0 scale at 125, 50 to 175, 100
3.0 scale at 200, 50 to 250, 100
Can't put this in comment so here it is in form of answer.
Anyone trying to use #olevegard solution please be aware that this scales ONLY SDL_RenderDrawPoints calls - ie. for example it's not working for diagonal lines
You can change SDL_RenderDrawPoints for SDL_RenderDrawLines and see result as in this screenshots (I've added aditional level scale = 6;)
SDL_RenderDrawLines
SDL_RenderDrawPoints
I got that code to get the pixel color from current mouse position.
It works well but the only problem is, I can't get it from an d3d application...
I tried it few times, but it only get only black color -
Red: 0
Green: 0
Blue: 0
Here's my code -
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <d3d9.h>
HWND hWindow;
HDC hScreen;
HDC hdcMem;
HBITMAP hBitmap;
HGDIOBJ hOld;
int sX, sY, x, y;
BYTE* sData = 0;
POINT cursorPos;
int main()
{
int Red, Green, Blue;
hScreen = GetDC(hWindow);
sX = GetDeviceCaps(hScreen, HORZRES);
sY = GetDeviceCaps(hScreen, VERTRES);
hdcMem = CreateCompatibleDC (hScreen);
hBitmap = CreateCompatibleBitmap(hScreen, sX, sY);
BITMAPINFOHEADER bm = {0};
bm.biSize = sizeof(BITMAPINFOHEADER);
bm.biPlanes = 1;
bm.biBitCount = 32;
bm.biWidth = sX;
bm.biHeight = -sY;
bm.biCompression = BI_RGB;
bm.biSizeImage = 0; // 3 * sX * sY;
while (1) {
hOld = SelectObject(hdcMem, hBitmap);
BitBlt(hdcMem, 0, 0, sX, sY, hScreen, 0, 0, SRCCOPY);
SelectObject(hdcMem, hOld);
free(sData);
sData = (BYTE*)malloc(4 * sX * sY);
GetDIBits(hdcMem, hBitmap, 0, sY, sData, (BITMAPINFO*)&bm, DIB_RGB_COLORS);
GetCursorPos(&cursorPos);
x = cursorPos.x;
y = cursorPos.y;
Red = sData[4 * ( (y * sX) + x) +2];
Green = sData[4 * ( ( y * sX) + x) +1];
Blue = sData[4 * ( (y * sX) + x)];
printf("\nRed: %d\nGreen: %d\nBlue: %d\n", Red, Green, Blue);
Sleep(300);
}
}
Thanks!
Which kind of d3d application do you use? if the application use an Overlay surface, you can't get anything with code above. Overlay surface is widely used in Video players, it's totally different with normal surfaces in DirectX, the normal screen shot software can only catch data from primary surface, and Microsoft didn't provide any public interface to get data from Overlay surfaces, but some software can do this, the most common way is to hook DirectX, that's a different topic.
If your d3d application didn't use Overlay surface, you can use DiretX to get the data from screen, then get the pixel from the screen data you want.
Use CreateOffscreenPlainSurface to create an offscreen surface
Use GetFrontBufferData to get the data from screen
Lock the surface and read the pixel to get the color