world: bodies now stored in c-like array
[k8-jellyphysics.git] / src / main.cpp
blob997eab4da532c8185348403a0bfdc541fb339782
1 /*
2 * Copyright (c) 2007 Walaber
3 * Modified by Ketmar // Invisible Vector
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
28 #include "jelly/JellyPhysics.h"
29 #include "videolib/videolib.h"
32 ////////////////////////////////////////////////////////////////////////////////
33 static float scale_x = 19.0f;
34 static float scale_y = 20.0f;
35 static float center_x = -21.0f;
36 static float center_y = -20.0f;
39 static inline int x2s (float x) { return (x-center_x)*scale_x; }
40 static inline int y2s (float y) { return SCR_WIDTH-(y-center_y)*scale_y; }
42 static inline float s2x (int x) { return ((float)x/scale_x)+center_x; }
43 static inline float s2y (int y) { return ((float)(SCR_WIDTH-y)/scale_y)+center_y; }
46 static void dll (float x0, float y0, float x1, float y1, Uint32 clr) {
47 x0 = x2s(x0);
48 y0 = y2s(y0);
49 x1 = x2s(x1);
50 y1 = y2s(y1);
51 draw_line(x0, y0, x1, y1, clr);
55 ////////////////////////////////////////////////////////////////////////////////
56 using namespace JellyPhysics;
59 ////////////////////////////////////////////////////////////////////////////////
60 // simple inherited classes, to add gravity force
61 class FallingBody : public SpringBody {
62 public:
63 FallingBody (
64 World *w, ClosedShape &s, float massPerPoint,
65 float edgeSpringK, float edgeSpringDamp,
66 const Vector2 &pos, float angle,
67 const Vector2 &scale, bool kinematic=false
68 ) : SpringBody(w, s, massPerPoint, edgeSpringK, edgeSpringDamp, pos, angle, scale, kinematic) {}
70 FallingBody (
71 World *w, const ClosedShape &shape, float massPerPoint,
72 float shapeSpringK, float shapeSpringDamp,
73 float edgeSpringK, float edgeSpringDamp,
74 const Vector2 &pos, float angleinRadians,
75 const Vector2 &scale, bool kinematic=false
76 ) : SpringBody(w, shape, massPerPoint, shapeSpringK, shapeSpringDamp, edgeSpringK, edgeSpringDamp, pos, angleinRadians, scale, kinematic) {}
78 virtual void accumulateExternalForces () {
79 // gravity!
80 for (unsigned int i = 0; i < mPointMasses.size(); ++i) mPointMasses[i].Force += Vector2(0.0f, -9.8f*mPointMasses[i].mass());
85 class FallingPressureBody : public PressureBody {
86 public:
87 FallingPressureBody (
88 World *w, const ClosedShape &s, float mpp,
89 float gasPressure, float shapeK, float shapeD,
90 float edgeK, float edgeD,
91 const Vector2 &pos, float angleInRadians, const Vector2 &scale,
92 bool kinematic=false) : PressureBody(w, s, mpp, gasPressure, shapeK, shapeD, edgeK, edgeD, pos, angleInRadians, scale, kinematic) {}
94 virtual void accumulateExternalForces () {
95 // gravity!
96 for (unsigned int i = 0; i < mPointMasses.size(); ++i) mPointMasses[i].Force += Vector2(0.0f, -9.8f*mPointMasses[i].mass());
101 ////////////////////////////////////////////////////////////////////////////////
102 static World *mWorld;
105 static void createI (float x, float y) {
106 // this is a complex body, in the shape of a capital "I", and connected with many internal springs.
107 ClosedShape shape;
108 shape.begin();
109 shape.addVertex(Vector2(-1.5f, 2.0f));
110 shape.addVertex(Vector2(-0.5f, 2.0f));
111 shape.addVertex(Vector2( 0.5f, 2.0f));
112 shape.addVertex(Vector2( 1.5f, 2.0f));
113 shape.addVertex(Vector2( 1.5f, 1.0f));
114 shape.addVertex(Vector2( 0.5f, 1.0f));
115 shape.addVertex(Vector2( 0.5f, -1.0f));
116 shape.addVertex(Vector2( 1.5f, -1.0f));
117 shape.addVertex(Vector2( 1.5f, -2.0f));
118 shape.addVertex(Vector2( 0.5f, -2.0f));
119 shape.addVertex(Vector2(-0.5f, -2.0f));
120 shape.addVertex(Vector2(-1.5f, -2.0f));
121 shape.addVertex(Vector2(-1.5f, -1.0f));
122 shape.addVertex(Vector2(-0.5f, -1.0f));
123 shape.addVertex(Vector2(-0.5f, 1.0f));
124 shape.addVertex(Vector2(-1.5f, 1.0f));
125 shape.finish();
127 FallingBody *body = new FallingBody(mWorld, shape, 1.0f, 150.0f, 5.0f, 300.0f, 15.0f, Vector2(x, y), 0.0f, Vector2::One);
128 body->addInternalSpring(0, 14, 300.0f, 10.0f);
129 body->addInternalSpring(1, 14, 300.0f, 10.0f);
130 body->addInternalSpring(1, 15, 300.0f, 10.0f);
131 body->addInternalSpring(1, 5, 300.0f, 10.0f);
132 body->addInternalSpring(2, 14, 300.0f, 10.0f);
133 body->addInternalSpring(2, 5, 300.0f, 10.0f);
134 body->addInternalSpring(1, 5, 300.0f, 10.0f);
135 body->addInternalSpring(14, 5, 300.0f, 10.0f);
136 body->addInternalSpring(2, 4, 300.0f, 10.0f);
137 body->addInternalSpring(3, 5, 300.0f, 10.0f);
138 body->addInternalSpring(14, 6, 300.0f, 10.0f);
139 body->addInternalSpring(5, 13, 300.0f, 10.0f);
140 body->addInternalSpring(13, 6, 300.0f, 10.0f);
141 body->addInternalSpring(12, 10, 300.0f, 10.0f);
142 body->addInternalSpring(13, 11, 300.0f, 10.0f);
143 body->addInternalSpring(13, 10, 300.0f, 10.0f);
144 body->addInternalSpring(13, 9, 300.0f, 10.0f);
145 body->addInternalSpring(6, 10, 300.0f, 10.0f);
146 body->addInternalSpring(6, 9, 300.0f, 10.0f);
147 body->addInternalSpring(6, 8, 300.0f, 10.0f);
148 body->addInternalSpring(7, 9, 300.0f, 10.0f);
152 static void createBall (float x, float y) {
153 // pressure body: similar to a SpringBody, but with internal pressurized gas to help maintain shape
154 ClosedShape ball;
155 ball.begin();
156 for (int i = 0; i < 360; i += 20) {
157 ball.addVertex(Vector2(cosf(degToRad((float)-i)), sinf(degToRad((float)-i))));
159 ball.finish();
160 new FallingPressureBody(mWorld, ball, 1.0f, 40.0f, 10.0f, 1.0f, 300.0f, 20.0f, Vector2(x, y), 0, Vector2::One);
164 static void initialize (void) {
165 // create physics world
166 mWorld = new World();
167 // static ground object
168 // all Closed Shape objects are assumed to be a list of lines going from point to point, with the last point
169 // connecting back to the first point to close the shape. this is a simple rectangle to represent the ground for this demo.
170 // ClosedShape objects are automatically "centered" when you call finish(), and that center becomes the center when
171 // setting the position of the object.
172 ClosedShape groundShape;
173 groundShape.begin();
175 groundShape.addVertex(Vector2(-20.0f, -1.0f));
176 groundShape.addVertex(Vector2(-20.0f, 1.0f));
177 groundShape.addVertex(Vector2( 20.0f, 1.0f));
178 groundShape.addVertex(Vector2( 20.0f, -1.0f));
180 groundShape.addVertex(Vector2(-20.0f, -1.0f));
181 groundShape.addVertex(Vector2(-20.0f, 3.0f));
182 groundShape.addVertex(Vector2(-10.0f, 0.6f));
183 groundShape.addVertex(Vector2( 0.0f, 0.3f));
184 groundShape.addVertex(Vector2( 10.0f, 0.6f));
185 groundShape.addVertex(Vector2( 20.0f, 1.0f));
186 groundShape.addVertex(Vector2( 20.0f, -1.0f));
187 groundShape.finish();
188 // make the body
189 // creating the body. since this is a static body, we can use the base class Body.
190 // setting the mass per point to 0.0f or INFINITY makes it immobile / static.
191 new Body(mWorld, groundShape, INFINITY, Vector2(0.0f, -5.0f), 0.0f, Vector2::One, false);
195 ////////////////////////////////////////////////////////////////////////////////
196 static void update (int elapsed_ms) {
197 sdl_frame_changed = 1;
198 // UPDATE the physics!
199 for (int i = 0; i < 10; ++i) mWorld->update(1/600.0f);
200 // remove out-of-bounds bodies
201 for (int f = mWorld->bodyCount()-1; f > 0; --f) {
202 Body *b = mWorld->body(f);
203 Vector2 p = b->getDerivedPosition();
204 Vector2 v = b->getDerivedVelocity();
205 //fprintf(stderr, "(%f,%f); v.X=%f; v.Y=%f\n", p.X, p.Y, v.X, v.Y);
206 if (p.Y < -8.0f && v.Y <= 0.0f) {
207 // kill it with fire!
208 delete b;
214 ////////////////////////////////////////////////////////////////////////////////
215 static void process_mousedown (SDL_MouseButtonEvent *ev) {
216 if (ev->button == SDL_BUTTON_LEFT) {
217 float x = s2x(ev->x);
218 float y = s2y(ev->y);
219 //fprintf(stderr, "x=%.15g; y=%.15g\n", x, y);
220 ClosedShape shape;
221 shape.begin();
222 shape.addVertex(Vector2(-1.0f, 0.0f));
223 shape.addVertex(Vector2( 0.0f, 1.0f));
224 shape.addVertex(Vector2( 1.0f, 0.0f));
225 shape.addVertex(Vector2( 0.0f, -1.0f));
226 shape.finish();
228 FallingBody *body = new FallingBody(mWorld, shape, 1.0f, 300.0f, 10.0f, Vector2(x, y), degToRad((float)rand()/RAND_MAX*360.0f), Vector2::One);
229 body->addInternalSpring(0, 2, 400.0f, 12.0f);
230 body->addInternalSpring(1, 3, 400.0f, 12.0f);
231 return;
234 if (ev->button == SDL_BUTTON_RIGHT) {
235 float x = s2x(ev->x);
236 float y = s2y(ev->y);
237 createI(x, y);
238 return;
241 if (ev->button == SDL_BUTTON_MIDDLE) {
242 float x = s2x(ev->x);
243 float y = s2y(ev->y);
244 createBall(x, y);
245 return;
250 static void rebuild (void) {
251 memset(sdl_vscr, 0, SCR_WIDTH*SCR_HEIGHT*sizeof(sdl_vscr[0]));
252 for (int f = 0; f < mWorld->bodyCount(); ++f) {
253 Body *b = mWorld->body(f);
254 Vector2List vrt = b->getVerticiesInWorld();
255 unsigned int pn = vrt.size()-1;
256 for (unsigned int vn = 0; vn < vrt.size(); pn = vn++) {
257 //fprintf(stderr, "vn=%u; x=%d; y=%d\n", vn, x2s(vrt[vn].X), y2s(vrt[vn].Y));
258 dll(vrt[pn].X, vrt[pn].Y, vrt[vn].X, vrt[vn].Y, rgb2col(255, 255, 255));
263 static char buf[128];
264 snprintf(buf, sizeof(buf), "body count: %d", mWorld->bodyCount());
265 //draw_str_pr(1, 1, "Meow!WO-OIl!", rgb2col(255, 255, 0), rgba2col(0, 0, 200, 200));
266 draw_str(1, 1, buf, rgb2col(255, 255, 0), mWorld->bodyCount());
272 ////////////////////////////////////////////////////////////////////////////////
273 static void process_keydown (SDL_KeyboardEvent *ev) {
274 if (ev->keysym.sym == SDLK_RETURN && (ev->keysym.mod&KMOD_ALT)) { switch_fullscreen(); return; }
275 if (ev->keysym.sym == SDLK_ESCAPE) { post_quit_message(); return; }
276 if (ev->keysym.sym == SDLK_SPACE) {
277 /* clear world */
278 while (mWorld->bodyCount() > 1) delete mWorld->body(mWorld->bodyCount()-1);
283 ////////////////////////////////////////////////////////////////////////////////
284 int main (int argc, char *argv[]) {
285 sdl_mag2x = 0;
286 videolib_args(&argc, argv);
287 if (videolib_init("JellyPhysics Demo 00") < 0) {
288 fprintf(stderr, "FATAL: can't initialize SDL!\n");
289 exit(1);
291 vl_fps = 60;
292 vl_rebuild = rebuild;
293 vl_update = update;
294 vl_process_keydown = process_keydown;
295 vl_process_mousedown = process_mousedown;
296 initialize();
297 vl_main_loop();
298 return 0;