1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
#include "Physics.h"
#include "ExtMath.h"
#include "Block.h"
#include "World.h"
#include "Platform.h"
#include "ExtMath.h"
#include "Funcs.h"
#include "Logger.h"
#include "Entity.h"
/*########################################################################################################################*
*----------------------------------------------------------AABB-----------------------------------------------------------*
*#########################################################################################################################*/
void AABB_Make(struct AABB* result, const Vec3* pos, const Vec3* size) {
result->Min.x = pos->x - size->x * 0.5f;
result->Min.y = pos->y;
result->Min.z = pos->z - size->z * 0.5f;
result->Max.x = pos->x + size->x * 0.5f;
result->Max.y = pos->y + size->y;
result->Max.z = pos->z + size->z * 0.5f;
}
void AABB_Offset(struct AABB* result, const struct AABB* bb, const Vec3* amount) {
Vec3_Add(&result->Min, &bb->Min, amount);
Vec3_Add(&result->Max, &bb->Max, amount);
}
cc_bool AABB_Intersects(const struct AABB* bb, const struct AABB* other) {
return
bb->Max.x >= other->Min.x && bb->Min.x <= other->Max.x &&
bb->Max.y >= other->Min.y && bb->Min.y <= other->Max.y &&
bb->Max.z >= other->Min.z && bb->Min.z <= other->Max.z;
}
cc_bool AABB_Contains(const struct AABB* parent, const struct AABB* child) {
return
child->Min.x >= parent->Min.x && child->Min.y >= parent->Min.y && child->Min.z >= parent->Min.z &&
child->Max.x <= parent->Max.x && child->Max.y <= parent->Max.y && child->Max.z <= parent->Max.z;
}
cc_bool AABB_ContainsPoint(const struct AABB* parent, const Vec3* P) {
return
P->x >= parent->Min.x && P->y >= parent->Min.y && P->z >= parent->Min.z &&
P->x <= parent->Max.x && P->y <= parent->Max.y && P->z <= parent->Max.z;
}
/*########################################################################################################################*
*------------------------------------------------------Intersection-------------------------------------------------------*
*#########################################################################################################################*/
static Vec3 Intersection_InverseRotate(Vec3 pos, struct Entity* target) {
pos = Vec3_RotateY(pos, -target->RotY * MATH_DEG2RAD);
pos = Vec3_RotateZ(pos, -target->RotZ * MATH_DEG2RAD);
pos = Vec3_RotateX(pos, -target->RotX * MATH_DEG2RAD);
return pos;
}
cc_bool Intersection_RayIntersectsRotatedBox(Vec3 origin, Vec3 dir, struct Entity* target, float* tMin, float* tMax) {
Vec3 delta, invDir;
struct AABB bb;
/* This is the rotated AABB of the model we want to test for intersection
*
/ \ we then perform a counter *---* and we can then do
====>* x * rotation to the rotated AABB | x | a standard AABB test
\ / and ray origin and direction *---* with the rotated ray
* /
/
*/
Vec3_Sub(&delta, &origin, &target->Position); /* delta = origin - target.Position */
delta = Intersection_InverseRotate(delta, target); /* delta = UndoRotation(delta) */
Vec3_Add(&origin, &delta, &target->Position); /* origin = delta + target.Position */
dir = Intersection_InverseRotate(dir, target);
Entity_GetPickingBounds(target, &bb);
invDir.x = 1.0f / dir.x;
invDir.y = 1.0f / dir.y;
invDir.z = 1.0f / dir.z;
return Intersection_RayIntersectsBox(origin, invDir, bb.Min, bb.Max, tMin, tMax);
}
cc_bool Intersection_RayIntersectsBox(Vec3 origin, Vec3 invDir, Vec3 min, Vec3 max, float* t0, float* t1) {
float tmin, tmax, tymin, tymax, tzmin, tzmax;
*t0 = 0; *t1 = 0;
if (invDir.x >= 0) {
tmin = (min.x - origin.x) * invDir.x;
tmax = (max.x - origin.x) * invDir.x;
} else {
tmin = (max.x - origin.x) * invDir.x;
tmax = (min.x - origin.x) * invDir.x;
}
if (invDir.y >= 0) {
tymin = (min.y - origin.y) * invDir.y;
tymax = (max.y - origin.y) * invDir.y;
} else {
tymin = (max.y - origin.y) * invDir.y;
tymax = (min.y - origin.y) * invDir.y;
}
if (tmin > tymax || tymin > tmax) return false;
if (tymin > tmin) tmin = tymin;
if (tymax < tmax) tmax = tymax;
if (invDir.z >= 0) {
tzmin = (min.z - origin.z) * invDir.z;
tzmax = (max.z - origin.z) * invDir.z;
} else {
tzmin = (max.z - origin.z) * invDir.z;
tzmax = (min.z - origin.z) * invDir.z;
}
if (tmin > tzmax || tzmin > tmax) return false;
if (tzmin > tmin) tmin = tzmin;
if (tzmax < tmax) tmax = tzmax;
*t0 = tmin; *t1 = tmax;
return tmin >= 0.0f;
}
/*########################################################################################################################*
*----------------------------------------------------Collisions finder----------------------------------------------------*
*#########################################################################################################################*/
#define SEARCHER_STATES_MIN 64
static struct SearcherState searcherDefaultStates[SEARCHER_STATES_MIN];
static cc_uint32 searcherCapacity = SEARCHER_STATES_MIN;
struct SearcherState* Searcher_States = searcherDefaultStates;
static void Searcher_QuickSort(int left, int right) {
struct SearcherState* keys = Searcher_States; struct SearcherState key;
while (left < right) {
int i = left, j = right;
float pivot = keys[(i + j) >> 1].tSquared;
/* partition the list */
while (i <= j) {
while (pivot > keys[i].tSquared) i++;
while (pivot < keys[j].tSquared) j--;
QuickSort_Swap_Maybe();
}
/* recurse into the smaller subset */
QuickSort_Recurse(Searcher_QuickSort);
}
}
int Searcher_FindReachableBlocks(struct Entity* entity, struct AABB* entityBB, struct AABB* entityExtentBB) {
Vec3 vel = entity->Velocity;
IVec3 min, max;
cc_uint32 elements;
struct SearcherState* curState;
int count;
BlockID block;
struct AABB blockBB;
float xx, yy, zz, tx, ty, tz;
int x, y, z;
Entity_GetBounds(entity, entityBB);
/* Exact maximum extent the entity can reach, and the equivalent map coordinates. */
entityExtentBB->Min.x = entityBB->Min.x + (vel.x < 0.0f ? vel.x : 0.0f);
entityExtentBB->Min.y = entityBB->Min.y + (vel.y < 0.0f ? vel.y : 0.0f);
entityExtentBB->Min.z = entityBB->Min.z + (vel.z < 0.0f ? vel.z : 0.0f);
entityExtentBB->Max.x = entityBB->Max.x + (vel.x > 0.0f ? vel.x : 0.0f);
entityExtentBB->Max.y = entityBB->Max.y + (vel.y > 0.0f ? vel.y : 0.0f);
entityExtentBB->Max.z = entityBB->Max.z + (vel.z > 0.0f ? vel.z : 0.0f);
IVec3_Floor(&min, &entityExtentBB->Min);
IVec3_Floor(&max, &entityExtentBB->Max);
elements = (max.x - min.x + 1) * (max.y - min.y + 1) * (max.z - min.z + 1);
if (elements > searcherCapacity) {
Searcher_Free();
searcherCapacity = elements;
Searcher_States = (struct SearcherState*)Mem_Alloc(elements, sizeof(struct SearcherState), "collision search states");
}
curState = Searcher_States;
/* Order loops so that we minimise cache misses */
for (y = min.y; y <= max.y; y++) {
for (z = min.z; z <= max.z; z++) {
for (x = min.x; x <= max.x; x++) {
block = World_GetPhysicsBlock(x, y, z);
if (Blocks.Collide[block] != COLLIDE_SOLID) continue;
xx = (float)x; yy = (float)y; zz = (float)z;
blockBB.Min = Blocks.MinBB[block];
blockBB.Min.x += xx; blockBB.Min.y += yy; blockBB.Min.z += zz;
blockBB.Max = Blocks.MaxBB[block];
blockBB.Max.x += xx; blockBB.Max.y += yy; blockBB.Max.z += zz;
if (!AABB_Intersects(entityExtentBB, &blockBB)) continue; /* necessary for non whole blocks. (slabs) */
Searcher_CalcTime(&vel, entityBB, &blockBB, &tx, &ty, &tz);
if (tx > 1.0f || ty > 1.0f || tz > 1.0f) continue;
curState->x = (x << 3) | (block & 0x007);
curState->y = (y << 4) | ((block & 0x078) >> 3);
curState->z = (z << 3) | ((block & 0x380) >> 7);
curState->tSquared = tx * tx + ty * ty + tz * tz;
curState++;
}
}
}
count = (int)(curState - Searcher_States);
if (count) Searcher_QuickSort(0, count - 1);
return count;
}
void Searcher_CalcTime(Vec3* vel, struct AABB *entityBB, struct AABB* blockBB, float* tx, float* ty, float* tz) {
float dx = vel->x > 0.0f ? blockBB->Min.x - entityBB->Max.x : entityBB->Min.x - blockBB->Max.x;
float dy = vel->y > 0.0f ? blockBB->Min.y - entityBB->Max.y : entityBB->Min.y - blockBB->Max.y;
float dz = vel->z > 0.0f ? blockBB->Min.z - entityBB->Max.z : entityBB->Min.z - blockBB->Max.z;
if (entityBB->Max.x >= blockBB->Min.x && entityBB->Min.x <= blockBB->Max.x) {
*tx = 0.0f; /* Inlined XIntersects test */
} else {
*tx = vel->x == 0.0f ? MATH_LARGENUM : Math_AbsF(dx / vel->x);
}
if (entityBB->Max.y >= blockBB->Min.y && entityBB->Min.y <= blockBB->Max.y) {
*ty = 0.0f; /* Inlined YIntersects test */
} else {
*ty = vel->y == 0.0f ? MATH_LARGENUM : Math_AbsF(dy / vel->y);
}
if (entityBB->Max.z >= blockBB->Min.z && entityBB->Min.z <= blockBB->Max.z) {
*tz = 0.0f; /* Inlined ZIntersects test */
} else {
*tz = vel->z == 0.0f ? MATH_LARGENUM : Math_AbsF(dz / vel->z);
}
}
void Searcher_Free(void) {
if (Searcher_States != searcherDefaultStates) Mem_Free(Searcher_States);
Searcher_States = searcherDefaultStates;
searcherCapacity = SEARCHER_STATES_MIN;
}
|