]> git.localhorst.tv Git - gworm.git/blob - src/world/World.cpp
speed up rendering by caching world texture
[gworm.git] / src / world / World.cpp
1 #include "World.h"
2
3 #include "../graphics/const.h"
4
5
6 namespace gworm {
7
8 World::World(Vector<int> size)
9 : size(size)
10 , count(size.x * size.y)
11 , masses(count, 1000000000.0f)
12 , colors(count, Color(0x7F, 0x7F, 0x7F))
13 , colorDirty(true) {
14
15 }
16
17
18 void World::Update(float dt) {
19         constexpr float fricDyn = 0.75f;
20         constexpr float fricStat = 2.5f;
21         constexpr float dragFact = 0.05f;
22
23         for (Entity &e : entities) {
24                 const Vector<float> gravity = ForceAt(e.pos, e.mass);
25                 const Vector<float> drag = Rotate180(e.vel) * dragFact;
26                 // TODO: drag should be inverse square. and not onmipresent
27
28                 e.acc = (gravity + drag) / e.mass;
29                 e.Update(dt);
30
31                 Vector<float> at;
32                 if (WorldCollision(e, at)) {
33                         float speed = Length(e.vel);
34                         Vector<float> normVel = e.vel / speed;
35                         float steps = 0;
36                         while (MassAt(e.pos) > 0) {
37                                 e.pos -= normVel;
38                                 steps += 1.0f;
39                         }
40                         const Vector<float> normal = NormalAt(e.pos + normVel);
41                         e.vel = Reflect(e.vel, normal);
42                         speed = Length(e.vel);
43                         normVel = e.vel / speed;
44                         // some kind of friction, depends on angle to normal
45                         speed *= (fricDyn * (std::abs(Dot(normVel, normal))));
46                         if (speed > fricStat) {
47                                 speed -= fricStat;
48                                 e.vel = normVel * speed;
49                                 e.pos += normVel * steps;
50                         } else {
51                                 e.vel = Vector<float>(0, 0);
52                         }
53                 }
54         }
55 }
56
57
58 bool World::WorldCollision(const Entity &e, Vector<float> &at) const {
59         if (InBounds(e.pos) && MassAt(e.pos) > 0) {
60                 at = e.pos;
61                 return true;
62         } else {
63                 return false;
64         }
65 }
66
67 Vector<float> World::NormalAt(Vector<float> pos) const {
68         constexpr Vector<float> check[] = {
69                 {  0,        -2        },
70                 {  0.765367, -1.84776  },
71                 {  1.41421,  -1.41421  },
72                 {  1.84776,  -0.765367 },
73                 {  2,         0        },
74                 {  1.84776,   0.765367 },
75                 {  1.41421,   1.41421  },
76                 {  0.765367,  1.84776  },
77                 {  0,         2        },
78                 { -0.765367,  1.84776  },
79                 { -1.41421,   1.41421  },
80                 { -1.84776,   0.765367 },
81                 { -2,         0        },
82                 { -1.84776,  -0.765367 },
83                 { -1.41421,  -1.41421  },
84                 { -0.765367, -1.84776  },
85         };
86         Vector<float> normal;
87         for (auto v : check) {
88                 if (MassAt(pos + v) == 0) {
89                         normal += v;
90                 }
91         }
92         return Norm(normal);
93 }
94
95 //Vector<float> World::NormalAt(Vector<float> pos) const {
96 //      Vector<int> begin(pos - Vector<float>(3, 3));
97 //      Vector<int> end(pos + Vector<float>(3, 3));
98 //
99 //      Vector<float> normal;
100 //      for (Vector<int> cur(begin); cur.y < end.y; ++cur.y) {
101 //              for (cur.x = begin.x; cur.x < end.x; ++cur.x) {
102 //                      if (IsSurface(cur) > 0) {
103 //                              const Vector<float> dir = pos - Vector<float>(cur);
104 //                              normal += Rotate90(dir);
105 //                      }
106 //              }
107 //      }
108 //
109 //      return Norm(normal);
110 //}
111
112 bool World::IsSurface(Vector<int> pos) const {
113         return MassAt(pos) > 0 && (
114                         MassAt(pos - Vector<int>(1, 0)) == 0 ||
115                         MassAt(pos + Vector<int>(1, 0)) == 0 ||
116                         MassAt(pos - Vector<int>(0, 1)) == 0 ||
117                         MassAt(pos + Vector<int>(0, 1)) == 0);
118 }
119
120
121 Entity &World::AddEntity(const Entity &e) {
122         entities.emplace_back(e);
123         return entities.back();
124 }
125
126
127 // returns <1.37136364,1.37136734> for 1 mass at <0,0>
128 /*
129 Vector<float> World::ForceAt(Vector<float> p1, float m1) const {
130         Vector<float> force(0, 0);
131
132         for (int i = 0; i < count; ++i) {
133                 const Vector<float> p2(i % size.y, i / size.y);
134                 if (p1 == p2) continue;
135
136                 const Vector<float> diff(p2 - p1);
137                 const Vector<float> dir(Norm(diff));
138
139                 const float m2 = masses[i];
140                 const float r2 = Dot(diff, diff);
141
142                 const float mag = G * ((m1 * m2) / r2) * 2; // double because m2 is our reference frame
143
144                 force += dir * mag;
145         }
146
147         return force;
148 }
149 */
150
151 // returns <1.37136674,1.37136662> for 1 mass at <0,0>
152 // (should be less prone to rounding loss, i.e. more accurate)
153 Vector<float> World::ForceAt(Vector<float> p1, float m1) const {
154         Vector<float> force(0, 0);
155
156         for (Vector<int> p2(0, 0); p2.y < size.y; ++p2.y) {
157                 Vector<float> rowForce(0, 0);
158                 for (p2.x = 0; p2.x < size.x; ++p2.x) {
159                         const int i = Index(p2);
160                         if (p1 == Vector<float>(p2)) continue;
161
162                         const Vector<float> diff(Vector<float>(p2) - p1);
163                         const Vector<float> dir(Norm(diff));
164
165                         const float m2 = masses[i];
166                         const float r2 = Dot(diff, diff);
167
168                         const float mag = G * ((m1 * m2) / r2) * 2; // double because m2 is our reference frame
169
170                         rowForce += dir * mag;
171                 }
172                 force += rowForce;
173         }
174
175         return force;
176 }
177
178 }