demo: added more features
[k8-jellyphysics.git] / src / main.cpp
blob676aa1358fcd615cde837f08e91b530d8252b885
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
6 #include "jelly/JellyPhysics.h"
7 #include "videolib/videolib.h"
10 ////////////////////////////////////////////////////////////////////////////////
11 static float scale_x = 30.0f;
12 static float scale_y = 22.0f;
13 static float center_x = -12.0f;
14 static float center_y = -20.0f;
17 static inline int x2s (float x) { return (x-center_x)*scale_x; }
18 static inline int y2s (float y) { return SCR_WIDTH-(y-center_y)*scale_y; }
20 static inline float s2x (int x) { return ((float)x/scale_x)+center_x; }
21 static inline float s2y (int y) { return ((float)(SCR_WIDTH-y)/scale_y)+center_y; }
24 static void dll (float x0, float y0, float x1, float y1, Uint32 clr) {
25 x0 = x2s(x0);
26 y0 = y2s(y0);
27 x1 = x2s(x1);
28 y1 = y2s(y1);
29 draw_line(x0, y0, x1, y1, clr);
33 ////////////////////////////////////////////////////////////////////////////////
34 using namespace JellyPhysics;
37 ////////////////////////////////////////////////////////////////////////////////
38 // simple inherited classes, to add gravity force
39 class FallingBody : public SpringBody {
40 public:
41 FallingBody (
42 World *w, ClosedShape &s, float massPerPoint,
43 float edgeSpringK, float edgeSpringDamp,
44 const Vector2 &pos, float angle, const Vector2 &scale
45 ) : SpringBody(w, s, massPerPoint, edgeSpringK, edgeSpringDamp, pos, angle, scale, false) {}
47 FallingBody (
48 World *w, const ClosedShape &shape, float massPerPoint,
49 float shapeSpringK, float shapeSpringDamp,
50 float edgeSpringK, float edgeSpringDamp,
51 const Vector2 &pos, float angleinRadians,
52 const Vector2 &scale, bool kinematic=false
53 ) : SpringBody(w, shape, massPerPoint, shapeSpringK, shapeSpringDamp, edgeSpringK, edgeSpringDamp, pos, angleinRadians, scale, kinematic) {}
55 virtual void accumulateExternalForces () {
56 // gravity!
57 for (unsigned int i = 0; i < mPointMasses.size(); ++i) mPointMasses[i].Force += Vector2(0.0f, -9.8f*mPointMasses[i].mass());
62 class FallingPressureBody : public PressureBody {
63 public:
64 FallingPressureBody (
65 World *w, const ClosedShape &s, float mpp,
66 float gasPressure, float shapeK, float shapeD,
67 float edgeK, float edgeD,
68 const Vector2 &pos, float angleInRadians, const Vector2 &scale,
69 bool kinematic) : PressureBody(w, s, mpp, gasPressure, shapeK, shapeD, edgeK, edgeD, pos, angleInRadians, scale, kinematic) {}
71 virtual void accumulateExternalForces () {
72 // gravity!
73 for (unsigned int i = 0; i < mPointMasses.size(); ++i) mPointMasses[i].Force += Vector2(0.0f, -9.8f*mPointMasses[i].mass());
78 ////////////////////////////////////////////////////////////////////////////////
79 static World *mWorld;
82 static void createI (float x, float y) {
83 // this is a complex body, in the shape of a capital "I", and connected with many internal springs.
84 ClosedShape shape;
85 shape.begin();
86 shape.addVertex(Vector2(-1.5f, 2.0f));
87 shape.addVertex(Vector2(-0.5f, 2.0f));
88 shape.addVertex(Vector2( 0.5f, 2.0f));
89 shape.addVertex(Vector2( 1.5f, 2.0f));
90 shape.addVertex(Vector2( 1.5f, 1.0f));
91 shape.addVertex(Vector2( 0.5f, 1.0f));
92 shape.addVertex(Vector2( 0.5f, -1.0f));
93 shape.addVertex(Vector2( 1.5f, -1.0f));
94 shape.addVertex(Vector2( 1.5f, -2.0f));
95 shape.addVertex(Vector2( 0.5f, -2.0f));
96 shape.addVertex(Vector2(-0.5f, -2.0f));
97 shape.addVertex(Vector2(-1.5f, -2.0f));
98 shape.addVertex(Vector2(-1.5f, -1.0f));
99 shape.addVertex(Vector2(-0.5f, -1.0f));
100 shape.addVertex(Vector2(-0.5f, 1.0f));
101 shape.addVertex(Vector2(-1.5f, 1.0f));
102 shape.finish();
104 FallingBody *body = new FallingBody(mWorld, shape, 1.0f, 150.0f, 5.0f, 300.0f, 15.0f, Vector2(x, y), 0.0f, Vector2::One);
105 body->addInternalSpring(0, 14, 300.0f, 10.0f);
106 body->addInternalSpring(1, 14, 300.0f, 10.0f);
107 body->addInternalSpring(1, 15, 300.0f, 10.0f);
108 body->addInternalSpring(1, 5, 300.0f, 10.0f);
109 body->addInternalSpring(2, 14, 300.0f, 10.0f);
110 body->addInternalSpring(2, 5, 300.0f, 10.0f);
111 body->addInternalSpring(1, 5, 300.0f, 10.0f);
112 body->addInternalSpring(14, 5, 300.0f, 10.0f);
113 body->addInternalSpring(2, 4, 300.0f, 10.0f);
114 body->addInternalSpring(3, 5, 300.0f, 10.0f);
115 body->addInternalSpring(14, 6, 300.0f, 10.0f);
116 body->addInternalSpring(5, 13, 300.0f, 10.0f);
117 body->addInternalSpring(13, 6, 300.0f, 10.0f);
118 body->addInternalSpring(12, 10, 300.0f, 10.0f);
119 body->addInternalSpring(13, 11, 300.0f, 10.0f);
120 body->addInternalSpring(13, 10, 300.0f, 10.0f);
121 body->addInternalSpring(13, 9, 300.0f, 10.0f);
122 body->addInternalSpring(6, 10, 300.0f, 10.0f);
123 body->addInternalSpring(6, 9, 300.0f, 10.0f);
124 body->addInternalSpring(6, 8, 300.0f, 10.0f);
125 body->addInternalSpring(7, 9, 300.0f, 10.0f);
129 static void createBall (float x, float y) {
130 // pressure body: similar to a SpringBody, but with internal pressurized gas to help maintain shape
131 ClosedShape ball;
132 ball.begin();
133 for (int i = 0; i < 360; i += 20) {
134 ball.addVertex(Vector2(cosf(VectorTools::degToRad((float)-i)), sinf(VectorTools::degToRad((float)-i))));
136 ball.finish();
137 new FallingPressureBody(mWorld, ball, 1.0f, 40.0f, 10.0f, 1.0f, 300.0f, 20.0f, Vector2(x, y), 0, Vector2::One, false);
141 static void initialize (void) {
142 // create physics world
143 mWorld = new World();
144 // static ground object
145 // all Closed Shape objects are assumed to be a list of lines going from point to point, with the last point
146 // connecting back to the first point to close the shape. this is a simple rectangle to represent the ground for this demo.
147 // ClosedShape objects are automatically "centered" when you call finish(), and that center becomes the center when
148 // setting the position of the object.
149 ClosedShape groundShape;
150 groundShape.begin();
151 groundShape.addVertex(Vector2(-10.0f, -2.0f));
152 groundShape.addVertex(Vector2(-10.0f, 2.0f));
153 groundShape.addVertex(Vector2( 10.0f, 2.0f));
154 groundShape.addVertex(Vector2( 10.0f, -2.0f));
155 groundShape.finish();
156 // make the body
157 // creating the body. since this is a static body, we can use the base class Body.
158 // setting the mass per point to 0.0f or INFINITY makes it immobile / static.
159 new Body(mWorld, groundShape, INFINITY, Vector2(0.0f, -5.0f), 0.0f, Vector2::One, false);
163 ////////////////////////////////////////////////////////////////////////////////
164 static void update (int elapsed_ms) {
165 sdl_frame_changed = 1;
166 // UPDATE the physics!
167 for (int i = 0; i < 3; ++i) mWorld->update(1/200.0f);
171 ////////////////////////////////////////////////////////////////////////////////
172 static void process_mousedown (SDL_MouseButtonEvent *ev) {
173 if (ev->button == SDL_BUTTON_LEFT) {
174 float x = s2x(ev->x);
175 float y = s2y(ev->y);
176 //fprintf(stderr, "x=%.15g; y=%.15g\n", x, y);
177 ClosedShape shape;
178 shape.begin();
179 shape.addVertex(Vector2(-1.0f, 0.0f));
180 shape.addVertex(Vector2( 0.0f, 1.0f));
181 shape.addVertex(Vector2( 1.0f, 0.0f));
182 shape.addVertex(Vector2( 0.0f, -1.0f));
183 shape.finish();
185 FallingBody *body = new FallingBody(mWorld, shape, 1.0f, 300.0f, 10.0f, Vector2(x, y), VectorTools::degToRad((float)rand()/RAND_MAX*360.0f), Vector2::One);
186 body->addInternalSpring(0, 2, 400.0f, 12.0f);
187 body->addInternalSpring(1, 3, 400.0f, 12.0f);
188 return;
191 if (ev->button == SDL_BUTTON_RIGHT) {
192 float x = s2x(ev->x);
193 float y = s2y(ev->y);
194 createI(x, y);
195 return;
198 if (ev->button == SDL_BUTTON_MIDDLE) {
199 float x = s2x(ev->x);
200 float y = s2y(ev->y);
201 createBall(x, y);
202 return;
207 static void rebuild (void) {
208 memset(sdl_vscr, 0, SCR_WIDTH*SCR_HEIGHT*sizeof(sdl_vscr[0]));
209 for (int f = 0; f < mWorld->bodyCount(); ++f) {
210 Body *b = mWorld->getBody(f);
211 const ClosedShape &shp = b->getBaseShape();
212 Vector2List vrt = shp.transformVertices(b->getDerivedPosition(), b->getDerivedAngle(), b->getScale());
213 unsigned int pn = vrt.size()-1;
214 for (unsigned int vn = 0; vn < vrt.size(); pn = vn++) {
215 //fprintf(stderr, "vn=%u; x=%d; y=%d\n", vn, x2s(vrt[vn].X), y2s(vrt[vn].Y));
216 dll(vrt[pn].X, vrt[pn].Y, vrt[vn].X, vrt[vn].Y, rgb2col(255, 255, 255));
221 static char buf[128];
222 snprintf(buf, sizeof(buf), "body count: %d", mWorld->bodyCount());
223 //draw_str_pr(1, 1, "Meow!WO-OIl!", rgb2col(255, 255, 0), rgba2col(0, 0, 200, 200));
224 draw_str(1, 1, buf, rgb2col(255, 255, 0), mWorld->bodyCount());
230 ////////////////////////////////////////////////////////////////////////////////
231 static void process_keydown (SDL_KeyboardEvent *ev) {
232 if (ev->keysym.sym == SDLK_RETURN && (ev->keysym.mod&KMOD_ALT)) { switch_fullscreen(); return; }
233 if (ev->keysym.sym == SDLK_ESCAPE) { post_quit_message(); return; }
234 if (ev->keysym.sym == SDLK_SPACE) {
235 /* clear world */
236 while (mWorld->bodyCount() > 1) delete mWorld->getBody(mWorld->bodyCount()-1);
241 ////////////////////////////////////////////////////////////////////////////////
242 int main (int argc, char *argv[]) {
243 sdl_mag2x = 0;
244 videolib_args(&argc, argv);
245 if (videolib_init("JellyPhysics Demo 00") < 0) {
246 fprintf(stderr, "FATAL: can't initialize SDL!\n");
247 exit(1);
249 vl_fps = 60;
250 vl_rebuild = rebuild;
251 vl_update = update;
252 vl_process_keydown = process_keydown;
253 vl_process_mousedown = process_mousedown;
254 initialize();
255 vl_main_loop();
256 return 0;