Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <windows.h>
- #include <cmath>
- /* The cBall class represents a point in a 2D space. */
- class cBall
- {
- public:
- double xp, yp; /* The ball previous position. */
- double x, y; /* The ball current position. */
- cBall(double x, double y)
- {
- this->xp = x; /* These two lines mean */
- this->yp = y; /* that the ball is not moving at first. */
- this->x = x;
- this->y = y;
- }
- void verlet()
- {
- /* Calculate velocity from the ball previous and current position.
- Actually, this isn't velocity but the product of velocity and the time step. */
- double vx = x - xp;
- double vy = y - yp;
- /* Calculate the ball future position. */
- double xn = x + vx;
- double yn = y + vy;
- /* Apply changes in the ball previous and current position. */
- xp = x;
- yp = y;
- x = xn;
- y = yn;
- }
- };
- /* The cSpring class represents a link between two balls. */
- class cSpring
- {
- public:
- cBall *b1, *b2; /* Pointers to two ball objects. */
- double l; /* The spring resting distance. */
- cSpring(cBall *b1, cBall *b2, double l)
- {
- this->b1 = b1;
- this->b2 = b2;
- this->l = l;
- }
- void solve()
- {
- /* The solve method repels the linked balls if they are too close to each other
- and attracts them if they are to far from each other. */
- double dx = b2->x - b1->x;
- double dy = b2->y - b1->y;
- double dl = sqrt(dx*dx + dy*dy); /* The distance between two balls. */
- double C = 0.0;
- if(dl != 0.0)
- C = 0.3 * (l - dl) / dl;
- /* If the distance between the balls is equal to the resting distance,
- the C equals 0 and the balls neither repel nor attract each other.
- If the distance between the balls is smaller than the resting distance,
- the C is positive and the balls repel each other.
- If the distance between the balls is greater than the resting distance,
- the C is negative and the balls attract each other. */
- double rx = C*dx;
- double ry = C*dy;
- b1->x -= rx;
- b1->y -= ry;
- b2->x += rx;
- b2->y += ry;
- }
- };
- /* The cSoftBody class represents the soft body consisting of one centre ball
- and four side balls linked to the centre ball with four springs. */
- class cSoftBody
- {
- public:
- cBall *balls[5]; /* Array of pointers to the balls. */
- cSpring *springs[4]; /* Array of pointers to the springs. */
- double worldW, worldH; /* Screen resolution (width and height) in pixels. */
- double R; /* The radius of the undeformed soft body. */
- cSoftBody()
- {
- R = 50.0;
- worldW = GetSystemMetrics(SM_CXSCREEN); /* Assign the screen width and height */
- worldH = GetSystemMetrics(SM_CYSCREEN); /* to the worldW and worldH variables. */
- /* The position of the screen centre in pixels. */
- double cx = worldW / 2.0;
- double cy = worldH / 2.0;
- /* The position of each ball is given in the screen coordinates
- and the centre ball is placed in the middle of the screen. */
- balls[0] = new cBall(cx, cy);
- balls[1] = new cBall(cx - R, cy);
- balls[2] = new cBall(cx, cy - R);
- balls[3] = new cBall(cx + R, cy);
- balls[4] = new cBall(cx, cy + R);
- for(int i = 0; i < 4; i++)
- {
- /* Each spring links the centre ball to one of the side balls. */
- springs[i] = new cSpring(balls[0], balls[i+1], R);
- }
- }
- ~cSoftBody()
- {
- for(int i = 0; i < 4; i++)
- {
- delete balls[i];
- delete springs[i];
- }
- delete balls[4];
- }
- void applyVelocity(double vx, double vy, double dt)
- {
- /* The applyVelocity method adds velocity to each ball
- by modifying its previous position.
- The velocity should be given in pixels per second. */
- for(int i = 0; i < 5; i++)
- {
- balls[i]->xp = balls[i]->x - vx*dt;
- balls[i]->yp = balls[i]->y - vy*dt;
- }
- }
- void loop()
- {
- /* Solve the constraint for each spring. */
- for(int i = 0; i < 4; i++)
- {
- springs[i]->solve();
- }
- for(int i = 0; i < 5; i++)
- {
- /* Solve the equation of motion for each ball. */
- balls[i]->verlet();
- /* React when a ball leaves the screen. */
- if(balls[i]->x < 0.0)
- balls[i]->x = 0.0;
- if(balls[i]->y < 0.0)
- balls[i]->y = 0.0;
- if(balls[i]->x > worldW)
- balls[i]->x = worldW;
- if(balls[i]->y > worldH)
- balls[i]->y = worldH;
- }
- /* The following piece of code makes sure that
- the left ball and the right ball can only move
- in the x direction in relation to the centre ball
- and that the top ball and the bottom ball can only move
- in the y direction in relation to the centre ball. */
- balls[1]->y = balls[0]->y;
- balls[2]->x = balls[0]->x;
- balls[3]->y = balls[0]->y;
- balls[4]->x = balls[0]->x;
- }
- };
- /* Create an object of the cSoftBody class. */
- cSoftBody body;
- /* This is where all the input to the window goes to */
- LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
- {
- switch(Message)
- {
- /* Upon destruction, tell the main thread to stop */
- case WM_DESTROY:
- {
- PostQuitMessage(0);
- break;
- }
- case WM_TIMER:
- {
- /* Predict the next state of the body. */
- body.loop();
- /* Create the following variables for an easier access. */
- double pl = body.balls[1]->x;
- double pt = body.balls[2]->y;
- double pr = body.balls[3]->x;
- double pb = body.balls[4]->y;
- double pcx = body.balls[0]->x;
- double pcy = body.balls[0]->y;
- double R = body.R;
- /* Move the window so that its centre is where the centre ball is.
- The width and height of the window should be four times bigger
- than the radius of the undeformed soft body.
- The window should be on top of everything. */
- SetWindowPos(hwnd, HWND_TOPMOST, pcx-2*R, pcy-2*R, 4*R, 4*R, SWP_SHOWWINDOW);
- /* Create an elliptic region.
- Its position and dimensions should be given in the window coordinates.
- The left, top, right and bottom ball specifies respectively
- the left, top, right and bottom edge of the region bounding box. */
- HRGN ellipse = CreateEllipticRgn(2*R-pcx+pl, 2*R-pcy+pt, 2*R-pcx+pr, 2*R-pcy+pb);
- SetWindowRgn(hwnd, ellipse, TRUE);
- break;
- }
- /* All other messages (a lot of them) are processed using default procedures */
- default:
- return DefWindowProc(hwnd, Message, wParam, lParam);
- }
- return 0;
- }
- /* The 'main' function of Win32 GUI programs: this is where execution starts */
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
- {
- body.applyVelocity(500.0, 500.0, 0.04);
- WNDCLASSEX wc; /* A properties struct of our window */
- HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
- MSG Msg; /* A temporary location for all messages */
- /* zero out the struct and set the stuff we want to modify */
- memset(&wc,0,sizeof(wc));
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.lpfnWndProc = WndProc; /* This is where we will send messages to */
- wc.hInstance = hInstance;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = CreateSolidBrush(RGB(255, 0, 0)); /* Make the window red. */
- wc.lpszClassName = "WindowClass";
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* Load a standard icon */
- wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); /* use the name "A" to use the project icon */
- if(!RegisterClassEx(&wc))
- {
- MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
- return 0;
- }
- hwnd = CreateWindowEx(0,"WindowClass","Caption",WS_POPUP,
- body.worldW/2.0, /* x */
- body.worldH/2.0, /* y */
- 4*body.R, /* width */
- 4*body.R, /* height */
- NULL,NULL,hInstance,NULL);
- if(hwnd == NULL)
- {
- MessageBox(NULL, "Window Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
- return 0;
- }
- /* Loop the simulation every 40 milliseconds. */
- SetTimer(hwnd, 1, 40, (TIMERPROC) NULL);
- /*
- This is the heart of our program where all input is processed and
- sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
- this loop will not produce unreasonably high CPU usage
- */
- while(GetMessage(&Msg, NULL, 0, 0) > 0) { /* If no error is received... */
- TranslateMessage(&Msg); /* Translate key codes to chars if present */
- DispatchMessage(&Msg); /* Send it to WndProc */
- }
- return Msg.wParam;
- }
Advertisement
Add Comment
Please, Sign In to add comment