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
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
) {
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
{
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
) {}
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 () {
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
{
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 () {
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.
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
));
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
156 for (int i
= 0; i
< 360; i
+= 20) {
157 ball
.addVertex(Vector2(cosf(degToRad((float)-i
)), sinf(degToRad((float)-i
))));
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
;
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();
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!
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);
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
));
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
);
234 if (ev
->button
== SDL_BUTTON_RIGHT
) {
235 float x
= s2x(ev
->x
);
236 float y
= s2y(ev
->y
);
241 if (ev
->button
== SDL_BUTTON_MIDDLE
) {
242 float x
= s2x(ev
->x
);
243 float y
= s2y(ev
->y
);
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
) {
278 while (mWorld
->bodyCount() > 1) delete mWorld
->body(mWorld
->bodyCount()-1);
283 ////////////////////////////////////////////////////////////////////////////////
284 int main (int argc
, char *argv
[]) {
286 videolib_args(&argc
, argv
);
287 if (videolib_init("JellyPhysics Demo 00") < 0) {
288 fprintf(stderr
, "FATAL: can't initialize SDL!\n");
292 vl_rebuild
= rebuild
;
294 vl_process_keydown
= process_keydown
;
295 vl_process_mousedown
= process_mousedown
;