102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
dttr_util_collision.h
Go to the documentation of this file.
1
7
8#ifndef DTTR_UTIL_COLLISION_H
9#define DTTR_UTIL_COLLISION_H
10
11#include <stdbool.h>
12#include <stddef.h>
13#include <stdint.h>
14
15#include <dttr_core.h>
16#ifndef DTTR_SDK_ENABLE_UNSTABLE
17#error "Define DTTR_SDK_ENABLE_UNSTABLE before including dttr_util_collision.h"
18#endif
19#include <dttr_pcdogs.h>
20#include <dttr_util_mem.h>
21
22#ifdef __cplusplus
23extern "C" {
24#endif
25
27#define DTTR_UTIL_COLLISION_Q12_ONE 4096
28
32#define DTTR_UTIL_COLLISION_VERTEX_WORLD_SCALE 64
33
36#define DTTR_UTIL_COLLISION_MAX_VERTICES 4096u
37#define DTTR_UTIL_COLLISION_MAX_POLYGONS 8192u
38
41#define DTTR_UTIL_COLLISION_ADJ_FACE_MIN_SIZE 0x14u
42
45#define DTTR_UTIL_COLLISION_VERTEX_WALL_TAG_OFFSET 0x0bu
46
51) {
52 return (polygon->flags & 0x1u) != 0u ? 3u : 4u;
53}
54
66) {
67 if (!node || !vertex || !out_world) {
68 return false;
69 }
70
71 int32_t x = (int32_t)vertex->x;
72 int32_t y = (int32_t)vertex->y;
73 int32_t z = (int32_t)vertex->z;
74 if ((node->flags & 0x22u) != 0u) {
75 const int32_t rx = x;
76 const int32_t ry = y;
77 const int32_t rz = z;
79 x = (int32_t)(((int64_t)rx * m->m00 + (int64_t)ry * m->m01 + (int64_t)rz * m->m02)
81 y = (int32_t)(((int64_t)rx * m->m10 + (int64_t)ry * m->m11 + (int64_t)rz * m->m12)
83 z = (int32_t)(((int64_t)rx * m->m20 + (int64_t)ry * m->m21 + (int64_t)rz * m->m22)
85 }
86
87 const int64_t wx = (int64_t)node->origin.x
89 const int64_t wy = (int64_t)node->origin.y
91 const int64_t wz = (int64_t)node->origin.z
93 if (wx < INT32_MIN || wx > INT32_MAX || wy < INT32_MIN || wy > INT32_MAX
94 || wz < INT32_MIN || wz > INT32_MAX) {
95 return false;
96 }
97
98 *out_world = (DTTR_PCDOGS_T_Math_Vec3I32){
99 .x = (int32_t)wx,
100 .y = (int32_t)wy,
101 .z = (int32_t)wz,
102 };
103 return true;
104}
105
114) {
115 if (!node || !polygon || !DTTR_Util_MemReadable(node, sizeof(*node))
116 || !node->polygons || !node->vertices || node->vertex_count == 0
118 return false;
119 }
120
121 const uint32_t polygon_count = node->polygon_count != 0u ? node->polygon_count
122 : node->vertex_count;
123
124 if (polygon_count > DTTR_UTIL_COLLISION_MAX_POLYGONS
126 node->polygons,
127 sizeof(node->polygons[0]) * polygon_count
128 )
130 node->vertices,
131 sizeof(node->vertices[0]) * node->vertex_count
132 )) {
133 return false;
134 }
135
136 const uintptr_t polygon_addr = (uintptr_t)polygon;
137 const uintptr_t polygons_begin = (uintptr_t)node->polygons;
138 const uintptr_t polygons_end = polygons_begin
139 + sizeof(node->polygons[0]) * polygon_count;
140 if (polygon_addr < polygons_begin || polygon_addr >= polygons_end) {
141 return false;
142 }
143
144 if ((polygon_addr - polygons_begin) % sizeof(node->polygons[0]) != 0u) {
145 return false;
146 }
147
148 // Records are quad-width, so all four indices must be valid, even for triangles.
149 for (uint32_t i = 0; i < 4u; ++i) {
150 if (polygon->vertex_indices[i] >= node->vertex_count) {
151 return false;
152 }
153 }
154
155 return true;
156}
157
166 const DTTR_PCDOGS_T_Collision_Polygon *polygon,
167 uint32_t edge_index,
168 int32_t *out_neighbor_edge
169) {
170 if (!node || !polygon || edge_index >= 4u || !polygon->adj_face_ptr
172 polygon->adj_face_ptr,
174 )) {
175 return NULL;
176 }
177
178 const uint16_t *adj_edges = (const uint16_t *)((const uint8_t *)polygon->adj_face_ptr
179 + 0x0c);
180 const uint16_t encoded = adj_edges[edge_index];
181 const uint32_t one_based_index = (uint32_t)encoded >> 2;
182 if (one_based_index == 0u || !node->polygons
183 || (node->polygon_count != 0u && one_based_index > node->polygon_count)) {
184 return NULL;
185 }
186
187 DTTR_PCDOGS_T_Collision_Polygon *neighbor = node->polygons + (one_based_index - 1u);
188 if (!DTTR_Util_MemReadable(neighbor, sizeof(*neighbor))) {
189 return NULL;
190 }
191
192 if (out_neighbor_edge) {
193 *out_neighbor_edge = (int32_t)(encoded & 0x3u);
194 }
195
196 return neighbor;
197}
198
199// Resolve a polygon edge to its endpoint vertex indices.
202 const DTTR_PCDOGS_T_Collision_Polygon *polygon,
203 uint32_t edge_index,
204 uint16_t *out_i0,
205 uint16_t *out_i1
206) {
207 if (edge_index >= 4u) {
208 return false;
209 }
210
211 const uint16_t i0 = polygon->vertex_indices[edge_index];
212 const uint16_t i1 = polygon->vertex_indices[(edge_index + 1u) & 3u];
213 if (i0 >= node->vertex_count || i1 >= node->vertex_count) {
214 return false;
215 }
216
217 *out_i0 = i0;
218 *out_i1 = i1;
219 return true;
220}
221
222// Read the per-vertex wall tag byte from a collision vertex record.
225) {
226 return ((const uint8_t *)vertex)[DTTR_UTIL_COLLISION_VERTEX_WALL_TAG_OFFSET];
227}
228
242 const DTTR_PCDOGS_T_Collision_Polygon *polygon,
243 uint32_t edge_index
244) {
245 if (!node || !polygon || !node->vertices
246 || edge_index >= DTTR_Util_CollisionPolygonEdgeCount(polygon)
247 || (polygon->flags & 0x4000u) == 0u) {
248 return false;
249 }
250
251 if ((polygon->flags & 0x400u) != 0u && polygon->plane_data
252 && DTTR_Util_MemReadable(polygon->plane_data, 1)
253 && (((const uint8_t *)polygon->plane_data)[0] & 0x1u) != 0u) {
254 return false;
255 }
256
257 uint16_t i0 = 0;
258 uint16_t i1 = 0;
259 if (!dttr_util_collision_edge_vertices(node, polygon, edge_index, &i0, &i1)
260 || i0 == i1) {
261 return false;
262 }
263
264 const uint8_t tag0 = dttr_util_collision_vertex_wall_tag(&node->vertices[i0]);
265 const uint8_t tag1 = dttr_util_collision_vertex_wall_tag(&node->vertices[i1]);
266 if (tag0 == 0u && tag1 == 0u) {
267 return false;
268 }
269
271 *neighbor = DTTR_Util_CollisionAdjacentPolygon(node, polygon, edge_index, NULL);
272 return neighbor == NULL || (neighbor->flags & 0x4u) == 0u;
273}
274
279 const DTTR_PCDOGS_T_Collision_Polygon *polygon,
280 uint32_t edge_index,
281 int32_t height_fp,
282 DTTR_PCDOGS_T_Math_Vec3I32 out_world[4]
283) {
284 if (!node || !polygon || !out_world
285 || edge_index >= DTTR_Util_CollisionPolygonEdgeCount(polygon)) {
286 return false;
287 }
288
289 uint16_t i0 = 0;
290 uint16_t i1 = 0;
291 if (!dttr_util_collision_edge_vertices(node, polygon, edge_index, &i0, &i1)) {
292 return false;
293 }
294
295 DTTR_PCDOGS_T_Math_Vec3I32 base0 = {0};
296 DTTR_PCDOGS_T_Math_Vec3I32 base1 = {0};
297 if (!DTTR_Util_CollisionVertexWorld(node, &node->vertices[i0], &base0)
298 || !DTTR_Util_CollisionVertexWorld(node, &node->vertices[i1], &base1)) {
299 return false;
300 }
301
302 const int64_t top0 = (int64_t)base0.y + height_fp;
303 const int64_t top1 = (int64_t)base1.y + height_fp;
304 if (top0 < INT32_MIN || top0 > INT32_MAX || top1 < INT32_MIN || top1 > INT32_MAX) {
305 return false;
306 }
307
308 out_world[0] = base0;
309 out_world[1] = base1;
310 out_world[2] = (DTTR_PCDOGS_T_Math_Vec3I32){base1.x, (int32_t)top1, base1.z};
311 out_world[3] = (DTTR_PCDOGS_T_Math_Vec3I32){base0.x, (int32_t)top0, base0.z};
312 return true;
313}
314
315#ifdef __cplusplus
316}
317#endif
318
319#endif // DTTR_UTIL_COLLISION_H
DTTR_Graphics_COM_Direct3DDevice7 void DWORD flags DWORD void DWORD DWORD float z
DTTR_Graphics_COM_DirectDrawSurface7 DWORD x
DTTR_Graphics_COM_DirectDrawSurface7 DWORD DWORD y
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
#define DTTR_UTIL_COLLISION_VERTEX_WORLD_SCALE
#define DTTR_UTIL_COLLISION_ADJ_FACE_MIN_SIZE
static bool DTTR_Util_CollisionEdgeIsWall(const DTTR_PCDOGS_T_Collision_Node *node, const DTTR_PCDOGS_T_Collision_Polygon *polygon, uint32_t edge_index)
#define DTTR_UTIL_COLLISION_Q12_ONE
Collision node transform matrices use this Q12 fixed-point unit.
static DTTR_PCDOGS_T_Collision_Polygon * DTTR_Util_CollisionAdjacentPolygon(const DTTR_PCDOGS_T_Collision_Node *node, const DTTR_PCDOGS_T_Collision_Polygon *polygon, uint32_t edge_index, int32_t *out_neighbor_edge)
static bool dttr_util_collision_edge_vertices(const DTTR_PCDOGS_T_Collision_Node *node, const DTTR_PCDOGS_T_Collision_Polygon *polygon, uint32_t edge_index, uint16_t *out_i0, uint16_t *out_i1)
static uint32_t DTTR_Util_CollisionPolygonEdgeCount(const DTTR_PCDOGS_T_Collision_Polygon *polygon)
static uint8_t dttr_util_collision_vertex_wall_tag(const DTTR_PCDOGS_T_Collision_Vertex *vertex)
static bool DTTR_Util_CollisionPolygonInNode(const DTTR_PCDOGS_T_Collision_Node *node, const DTTR_PCDOGS_T_Collision_Polygon *polygon)
#define DTTR_UTIL_COLLISION_MAX_POLYGONS
static bool DTTR_Util_CollisionVertexWorld(const DTTR_PCDOGS_T_Collision_Node *node, const DTTR_PCDOGS_T_Collision_Vertex *vertex, DTTR_PCDOGS_T_Math_Vec3I32 *out_world)
#define DTTR_UTIL_COLLISION_VERTEX_WALL_TAG_OFFSET
#define DTTR_UTIL_COLLISION_MAX_VERTICES
static bool DTTR_Util_CollisionWallEdgeQuad(const DTTR_PCDOGS_T_Collision_Node *node, const DTTR_PCDOGS_T_Collision_Polygon *polygon, uint32_t edge_index, int32_t height_fp, DTTR_PCDOGS_T_Math_Vec3I32 out_world[4])
static bool DTTR_Util_MemReadable(const void *ptr, size_t size)
DTTR_PCDOGS_T_Math_Matrix3x3I16 transform_matrix
DTTR_PCDOGS_T_Math_Vec3I32 origin
Offset 0x40.
DTTR_PCDOGS_T_Collision_Polygon * polygons
DTTR_PCDOGS_T_Collision_Vertex * vertices
uint16_t vertex_indices[4]
Offset 0x4.
DTTR_PCDOGS_T_Collision_Plane * plane_data
Offset 0x0.