1 #include "engine.h"
2
triintersect(tri & t,const vec & o,const vec & ray,float maxdist,float & dist,int mode,tri * noclip)3 bool BIH::triintersect(tri &t, const vec &o, const vec &ray, float maxdist, float &dist, int mode, tri *noclip)
4 {
5 vec p;
6 p.cross(ray, t.c);
7 float det = t.b.dot(p);
8 if(det == 0) return false;
9 vec r(o);
10 r.sub(t.a);
11 float u = r.dot(p) / det;
12 if(u < 0 || u > 1) return false;
13 vec q;
14 q.cross(r, t.b);
15 float v = ray.dot(q) / det;
16 if(v < 0 || u + v > 1) return false;
17 float f = t.c.dot(q) / det;
18 if(f < 0 || f > maxdist) return false;
19 if(!(mode&RAY_SHADOW) && &t >= noclip) return false;
20 if(t.tex && (mode&RAY_ALPHAPOLY)==RAY_ALPHAPOLY && (t.tex->alphamask || (loadalphamask(t.tex), t.tex->alphamask)))
21 {
22 int si = clamp(int(t.tex->xs * (t.tc[0] + u*(t.tc[2] - t.tc[0]) + v*(t.tc[4] - t.tc[0]))), 0, t.tex->xs-1),
23 ti = clamp(int(t.tex->ys * (t.tc[1] + u*(t.tc[3] - t.tc[1]) + v*(t.tc[5] - t.tc[1]))), 0, t.tex->ys-1);
24 if(!(t.tex->alphamask[ti*((t.tex->xs+7)/8) + si/8] & (1<<(si%8)))) return false;
25 }
26 if(!(mode&RAY_SHADOW))
27 {
28 extern vec hitsurface;
29 hitsurface.cross(t.b, t.c).normalize();
30 if(hitsurface.dot(ray) > 0) hitsurface.neg();
31 }
32 dist = f;
33 return true;
34 }
35
36 struct BIHStack
37 {
38 BIHNode *node;
39 float tmin, tmax;
40 };
41
traverse(const vec & o,const vec & ray,float maxdist,float & dist,int mode)42 bool BIH::traverse(const vec &o, const vec &ray, float maxdist, float &dist, int mode)
43 {
44 if(!numnodes) return false;
45
46 vec invray(ray.x ? 1/ray.x : 1e16f, ray.y ? 1/ray.y : 1e16f, ray.z ? 1/ray.z : 1e16f);
47 float tmin, tmax;
48 float t1 = (bbmin.x - o.x)*invray.x,
49 t2 = (bbmax.x - o.x)*invray.x;
50 if(invray.x > 0) { tmin = t1; tmax = t2; } else { tmin = t2; tmax = t1; }
51 t1 = (bbmin.y - o.y)*invray.y;
52 t2 = (bbmax.y - o.y)*invray.y;
53 if(invray.y > 0) { tmin = max(tmin, t1); tmax = min(tmax, t2); } else { tmin = max(tmin, t2); tmax = min(tmax, t1); }
54 t1 = (bbmin.z - o.z)*invray.z;
55 t2 = (bbmax.z - o.z)*invray.z;
56 if(invray.z > 0) { tmin = max(tmin, t1); tmax = min(tmax, t2); } else { tmin = max(tmin, t2); tmax = min(tmax, t1); }
57 if(tmin >= maxdist || tmin>=tmax) return false;
58 tmax = min(tmax, maxdist);
59
60 static vector<BIHStack> stack;
61 stack.setsizenodelete(0);
62
63 ivec order(ray.x>0 ? 0 : 1, ray.y>0 ? 0 : 1, ray.z>0 ? 0 : 1);
64 BIHNode *curnode = &nodes[0];
65 bool hit = false;
66 for(;;)
67 {
68 int axis = curnode->axis();
69 int nearidx = order[axis], faridx = nearidx^1;
70 float nearsplit = (curnode->split[nearidx] - o[axis])*invray[axis],
71 farsplit = (curnode->split[faridx] - o[axis])*invray[axis];
72
73 if(nearsplit <= tmin)
74 {
75 if(farsplit < tmax)
76 {
77 if(!curnode->isleaf(faridx))
78 {
79 curnode = &nodes[curnode->childindex(faridx)];
80 tmin = max(tmin, farsplit);
81 continue;
82 }
83 else if(triintersect(tris[curnode->childindex(faridx)], o, ray, maxdist, maxdist, mode, noclip))
84 {
85 if(mode&RAY_SHADOW) { dist = maxdist; return true; }
86 hit = true;
87 }
88 }
89 }
90 else if(curnode->isleaf(nearidx))
91 {
92 if(triintersect(tris[curnode->childindex(nearidx)], o, ray, maxdist, maxdist, mode, noclip))
93 {
94 if(mode&RAY_SHADOW) { dist = maxdist; return true; }
95 hit = true;
96 }
97 if(farsplit < tmax)
98 {
99 if(!curnode->isleaf(faridx))
100 {
101 curnode = &nodes[curnode->childindex(faridx)];
102 tmin = max(tmin, farsplit);
103 continue;
104 }
105 else if(triintersect(tris[curnode->childindex(faridx)], o, ray, maxdist, maxdist, mode, noclip))
106 {
107 if(mode&RAY_SHADOW) { dist = maxdist; return true; }
108 hit = true;
109 }
110 }
111 }
112 else
113 {
114 if(farsplit < tmax)
115 {
116 if(!curnode->isleaf(faridx))
117 {
118 BIHStack &save = stack.add();
119 save.node = &nodes[curnode->childindex(faridx)];
120 save.tmin = max(tmin, farsplit);
121 save.tmax = tmax;
122 }
123 else if(triintersect(tris[curnode->childindex(faridx)], o, ray, maxdist, maxdist, mode, noclip))
124 {
125 if(mode&RAY_SHADOW) { dist = maxdist; return true; }
126 hit = true;
127 }
128 }
129 curnode = &nodes[curnode->childindex(nearidx)];
130 tmax = min(tmax, nearsplit);
131 continue;
132 }
133 if(stack.empty()) { if(hit) { dist = maxdist; return true; } return false; }
134 BIHStack &restore = stack.pop();
135 curnode = restore.node;
136 tmin = restore.tmin;
137 tmax = restore.tmax;
138 }
139 }
140
141 static BIH::tri *sorttris = NULL;
142 static int sortaxis = 0;
143
bihsort(const ushort * x,const ushort * y)144 static int bihsort(const ushort *x, const ushort *y)
145 {
146 BIH::tri &xtri = sorttris[*x], &ytri = sorttris[*y];
147 float xmin = min(xtri.a[sortaxis], min(xtri.b[sortaxis], xtri.c[sortaxis])),
148 ymin = min(ytri.a[sortaxis], min(ytri.b[sortaxis], ytri.c[sortaxis]));
149 if(xmin < ymin) return -1;
150 if(xmin > ymin) return 1;
151 return 0;
152 }
153
build(vector<BIHNode> & buildnodes,ushort * indices,int numindices,int depth)154 void BIH::build(vector<BIHNode> &buildnodes, ushort *indices, int numindices, int depth)
155 {
156 maxdepth = max(maxdepth, depth);
157
158 vec vmin(1e16f, 1e16f, 1e16f), vmax(-1e16f, -1e16f, -1e16f);
159 loopi(numindices)
160 {
161 tri &tri = tris[indices[i]];
162 loopk(3)
163 {
164 float amin = min(tri.a[k], min(tri.b[k], tri.c[k])),
165 amax = max(tri.a[k], max(tri.b[k], tri.c[k]));
166 vmin[k] = min(vmin[k], amin);
167 vmax[k] = max(vmax[k], amax);
168 }
169 }
170 if(depth==1)
171 {
172 bbmin = vmin;
173 bbmax = vmax;
174 }
175
176 int axis = 2;
177 loopk(2) if(vmax[k] - vmin[k] > vmax[axis] - vmin[axis]) axis = k;
178
179 /*
180 sorttris = tris;
181 sortaxis = axis;
182 quicksort(indices, numindices, bihsort);
183 tri &median = tris[numindices/2];
184 float split = min(median.a[axis], min(median.b[axis], median.c[axis]));
185 */
186
187 float split = 0.5f*(vmax[axis] + vmin[axis]);
188
189 float splitleft = SHRT_MIN, splitright = SHRT_MAX;
190 int left, right;
191 for(left = 0, right = numindices; left < right;)
192 {
193 tri &tri = tris[indices[left]];
194 float amin = min(tri.a[axis], min(tri.b[axis], tri.c[axis])),
195 amax = max(tri.a[axis], max(tri.b[axis], tri.c[axis]));
196 if(max(split - amin, 0.0f) > max(amax - split, 0.0f))
197 {
198 ++left;
199 splitleft = max(splitleft, amax);
200 }
201 else
202 {
203 --right;
204 swap(indices[left], indices[right]);
205 splitright = min(splitright, amin);
206 }
207 }
208
209 if(!left || right==numindices)
210 {
211 sorttris = tris;
212 sortaxis = axis;
213 quicksort(indices, numindices, bihsort);
214
215 left = right = numindices/2;
216 splitleft = SHRT_MIN;
217 splitright = SHRT_MAX;
218 loopi(numindices)
219 {
220 tri &tri = tris[indices[i]];
221 if(i < left) splitleft = max(splitleft, max(tri.a[axis], max(tri.b[axis], tri.c[axis])));
222 else splitright = min(splitright, min(tri.a[axis], min(tri.b[axis], tri.c[axis])));
223 }
224 }
225
226 int node = buildnodes.length();
227 buildnodes.add();
228 buildnodes[node].split[0] = short(ceil(splitleft));
229 buildnodes[node].split[1] = short(floor(splitright));
230
231 if(left==1) buildnodes[node].child[0] = (axis<<14) | indices[0];
232 else
233 {
234 buildnodes[node].child[0] = (axis<<14) | buildnodes.length();
235 build(buildnodes, indices, left, depth+1);
236 }
237
238 if(numindices-right==1) buildnodes[node].child[1] = (1<<15) | (left==1 ? 1<<14 : 0) | indices[right];
239 else
240 {
241 buildnodes[node].child[1] = (left==1 ? 1<<14 : 0) | buildnodes.length();
242 build(buildnodes, &indices[right], numindices-right, depth+1);
243 }
244 }
245
BIH(vector<tri> * t)246 BIH::BIH(vector<tri> *t)
247 {
248 numtris = t[0].length() + t[1].length();
249 if(!numtris)
250 {
251 tris = NULL;
252 numnodes = 0;
253 nodes = NULL;
254 maxdepth = 0;
255 return;
256 }
257
258 tris = new tri[numtris];
259 noclip = &tris[t[0].length()];
260 memcpy(tris, t[0].getbuf(), t[0].length()*sizeof(tri));
261 memcpy(noclip, t[1].getbuf(), t[1].length()*sizeof(tri));
262
263 vector<BIHNode> buildnodes;
264 ushort *indices = new ushort[numtris];
265 loopi(numtris) indices[i] = i;
266
267 maxdepth = 0;
268
269 build(buildnodes, indices, numtris);
270
271 delete[] indices;
272
273 numnodes = buildnodes.length();
274 nodes = new BIHNode[numnodes];
275 memcpy(nodes, buildnodes.getbuf(), numnodes*sizeof(BIHNode));
276
277 // convert tri.b/tri.c to edges
278 loopi(numtris)
279 {
280 tri &tri = tris[i];
281 tri.b.sub(tri.a);
282 tri.c.sub(tri.a);
283 }
284 }
285
yawray(vec & o,vec & ray,float angle)286 static inline void yawray(vec &o, vec &ray, float angle)
287 {
288 angle *= RAD;
289 float c = cosf(angle), s = sinf(angle),
290 ox = o.x, oy = o.y,
291 rx = ray.x, ry = ray.y;
292 o.x = ox*c - oy*s;
293 o.y = oy*c + ox*s;
294 ray.x = rx*c - ry*s;
295 ray.y = ry*c + rx*s;
296 ray.normalize();
297 }
298
mmintersect(const extentity & e,const vec & o,const vec & ray,float maxdist,int mode,float & dist)299 bool mmintersect(const extentity &e, const vec &o, const vec &ray, float maxdist, int mode, float &dist)
300 {
301 model *m = loadmodel(NULL, e.attrs[0]);
302 if(!m) return false;
303 if(mode&RAY_SHADOW)
304 {
305 if(!m->shadow || e.lastemit || e.attrs[5]&MMT_NOSHADOW) return false;
306 }
307 else if((mode&RAY_ENTS)!=RAY_ENTS && !m->collide) return false;
308 if(!m->bih && !m->setBIH()) return false;
309 if(!maxdist) maxdist = 1e16f;
310 vec yo(o);
311 yo.sub(e.o);
312 float yaw = -180.0f-(float)(e.attrs[1]%360);
313 vec yray(ray);
314 if(yaw != 0) yawray(yo, yray, yaw);
315 if(m->bih->traverse(yo, yray, maxdist, dist, mode))
316 {
317 if(!(mode&RAY_SHADOW) && yaw != 0) hitsurface.rotate_around_z(-yaw*RAD);
318 return true;
319 }
320 return false;
321 }
322
323