4 bool BIH::triintersect(tri
&tri
, const vec
&o
, const vec
&ray
, float maxdist
, float &dist
, int mode
)
8 float det
= tri
.b
.dot(p
);
9 if(det
== 0) return false;
12 float u
= r
.dot(p
) / det
;
13 if(u
< 0 || u
> 1) return false;
16 float v
= ray
.dot(q
) / det
;
17 if(v
< 0 || u
+ v
> 1) return false;
18 float f
= tri
.c
.dot(q
) / det
;
19 if(f
< 0 || f
> maxdist
) return false;
20 if(tri
.tex
&& (mode
&RAY_ALPHAPOLY
)==RAY_ALPHAPOLY
)
22 if(!tri
.tex
->alphamask
)
24 loadalphamask(tri
.tex
);
25 if(!tri
.tex
->alphamask
) { dist
= f
; return true; }
27 float s
= tri
.tc
[0] + u
*(tri
.tc
[2] - tri
.tc
[0]) + v
*(tri
.tc
[4] - tri
.tc
[0]),
28 t
= tri
.tc
[1] + u
*(tri
.tc
[3] - tri
.tc
[1]) + v
*(tri
.tc
[5] - tri
.tc
[1]);
29 int si
= int(s
*tri
.tex
->xs
), ti
= int(t
*tri
.tex
->ys
);
30 if(!(tri
.tex
->alphamask
[ti
*((tri
.tex
->xs
+7)/8) + si
/8] & (1<<(si
%8)))) return false;
42 bool BIH::traverse(const vec
&o
, const vec
&ray
, float maxdist
, float &dist
, int mode
)
44 if(!numnodes
) return false;
46 vec
invray(ray
.x
? 1/ray
.x
: 1e16f
, ray
.y
? 1/ray
.y
: 1e16f
, ray
.z
? 1/ray
.z
: 1e16f
);
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
);
60 static vector
<BIHStack
> stack
;
61 stack
.setsizenodelete(0);
63 ivec
order(ray
.x
>0 ? 0 : 1, ray
.y
>0 ? 0 : 1, ray
.z
>0 ? 0 : 1);
64 BIHNode
*curnode
= &nodes
[0];
67 int axis
= curnode
->axis();
68 int nearidx
= order
[axis
], faridx
= nearidx
^1;
69 float nearsplit
= (curnode
->split
[nearidx
] - o
[axis
])*invray
[axis
],
70 farsplit
= (curnode
->split
[faridx
] - o
[axis
])*invray
[axis
];
76 if(!curnode
->isleaf(faridx
))
78 curnode
= &nodes
[curnode
->childindex(faridx
)];
79 tmin
= max(tmin
, farsplit
);
82 else if(triintersect(tris
[curnode
->childindex(faridx
)], o
, ray
, maxdist
, dist
, mode
)) return true;
85 else if(curnode
->isleaf(nearidx
))
87 if(triintersect(tris
[curnode
->childindex(nearidx
)], o
, ray
, maxdist
, dist
, mode
)) return true;
90 if(!curnode
->isleaf(faridx
))
92 curnode
= &nodes
[curnode
->childindex(faridx
)];
93 tmin
= max(tmin
, farsplit
);
96 else if(triintersect(tris
[curnode
->childindex(faridx
)], o
, ray
, maxdist
, dist
, mode
)) return true;
103 if(!curnode
->isleaf(faridx
))
105 BIHStack
&save
= stack
.add();
106 save
.node
= &nodes
[curnode
->childindex(faridx
)];
107 save
.tmin
= max(tmin
, farsplit
);
110 else if(triintersect(tris
[curnode
->childindex(faridx
)], o
, ray
, maxdist
, dist
, mode
)) return true;
112 curnode
= &nodes
[curnode
->childindex(nearidx
)];
113 tmax
= min(tmax
, nearsplit
);
116 if(stack
.empty()) return false;
117 BIHStack
&restore
= stack
.pop();
118 curnode
= restore
.node
;
124 static BIH::tri
*sorttris
= NULL
;
125 static int sortaxis
= 0;
127 static int bihsort(const ushort
*x
, const ushort
*y
)
129 BIH::tri
&xtri
= sorttris
[*x
], &ytri
= sorttris
[*y
];
130 float xmin
= min(xtri
.a
[sortaxis
], min(xtri
.b
[sortaxis
], xtri
.c
[sortaxis
])),
131 ymin
= min(ytri
.a
[sortaxis
], min(ytri
.b
[sortaxis
], ytri
.c
[sortaxis
]));
132 if(xmin
< ymin
) return -1;
133 if(xmin
> ymin
) return 1;
137 void BIH::build(vector
<BIHNode
> &buildnodes
, ushort
*indices
, int numindices
, int depth
)
139 maxdepth
= max(maxdepth
, depth
);
141 vec
vmin(1e16f
, 1e16f
, 1e16f
), vmax(-1e16f
, -1e16f
, -1e16f
);
144 tri
&tri
= tris
[indices
[i
]];
147 float amin
= min(tri
.a
[k
], min(tri
.b
[k
], tri
.c
[k
])),
148 amax
= max(tri
.a
[k
], max(tri
.b
[k
], tri
.c
[k
]));
149 vmin
[k
] = min(vmin
[k
], amin
);
150 vmax
[k
] = max(vmax
[k
], amax
);
160 loopk(2) if(vmax
[k
] - vmin
[k
] > vmax
[axis
] - vmin
[axis
]) axis
= k
;
165 qsort(indices, numindices, sizeof(ushort), (int (__cdecl *)(const void *, const void *))bihsort);
166 tri &median = tris[numindices/2];
167 float split = min(median.a[axis], min(median.b[axis], median.c[axis]));
170 float split
= 0.5f
*(vmax
[axis
] + vmin
[axis
]);
172 float splitleft
= SHRT_MIN
, splitright
= SHRT_MAX
;
174 for(left
= 0, right
= numindices
; left
< right
;)
176 tri
&tri
= tris
[indices
[left
]];
177 float amin
= min(tri
.a
[axis
], min(tri
.b
[axis
], tri
.c
[axis
])),
178 amax
= max(tri
.a
[axis
], max(tri
.b
[axis
], tri
.c
[axis
]));
179 if(max(split
- amin
, 0) > max(amax
- split
, 0))
182 splitleft
= max(splitleft
, amax
);
187 swap(ushort
, indices
[left
], indices
[right
]);
188 splitright
= min(splitright
, amin
);
192 if(!left
|| right
==numindices
)
196 qsort(indices
, numindices
, sizeof(ushort
), (int (__cdecl
*)(const void *, const void *))bihsort
);
198 left
= right
= numindices
/2;
199 splitleft
= SHRT_MIN
;
200 splitright
= SHRT_MAX
;
203 tri
&tri
= tris
[indices
[i
]];
204 if(i
< left
) splitleft
= max(splitleft
, max(tri
.a
[axis
], max(tri
.b
[axis
], tri
.c
[axis
])));
205 else splitright
= min(splitright
, min(tri
.a
[axis
], min(tri
.b
[axis
], tri
.c
[axis
])));
209 int node
= buildnodes
.length();
211 buildnodes
[node
].split
[0] = short(ceil(splitleft
));
212 buildnodes
[node
].split
[1] = short(floor(splitright
));
214 if(left
==1) buildnodes
[node
].child
[0] = (axis
<<14) | indices
[0];
217 buildnodes
[node
].child
[0] = (axis
<<14) | buildnodes
.length();
218 build(buildnodes
, indices
, left
, depth
+1);
221 if(numindices
-right
==1) buildnodes
[node
].child
[1] = (1<<15) | (left
==1 ? 1<<14 : 0) | indices
[right
];
224 buildnodes
[node
].child
[1] = (left
==1 ? 1<<14 : 0) | buildnodes
.length();
225 build(buildnodes
, &indices
[right
], numindices
-right
, depth
+1);
229 BIH::BIH(int _numtris
, tri
*_tris
)
241 tris
= new tri
[numtris
];
242 memcpy(tris
, _tris
, numtris
*sizeof(tri
));
244 vector
<BIHNode
> buildnodes
;
245 ushort
*indices
= new ushort
[numtris
];
246 loopi(numtris
) indices
[i
] = i
;
250 build(buildnodes
, indices
, numtris
);
254 numnodes
= buildnodes
.length();
255 nodes
= new BIHNode
[numnodes
];
256 memcpy(nodes
, buildnodes
.getbuf(), numnodes
*sizeof(BIHNode
));
258 // convert tri.b/tri.c to edges
267 static inline void yawray(vec
&o
, vec
&ray
, float angle
)
270 float c
= cosf(angle
), s
= sinf(angle
),
272 rx
= ox
+ray
.x
, ry
= oy
+ray
.y
;
275 ray
.x
= rx
*c
- ry
*s
- o
.x
;
276 ray
.y
= ry
*c
+ rx
*s
- o
.y
;
280 bool mmintersect(const extentity
&e
, const vec
&o
, const vec
&ray
, float maxdist
, int mode
, float &dist
)
282 model
*m
= loadmodel(NULL
, e
.attr2
);
286 if(!m
->shadow
|| checktriggertype(e
.attr3
, TRIG_COLLIDE
|TRIG_DISAPPEAR
)) return false;
288 else if((mode
&RAY_ENTS
)!=RAY_ENTS
&& !m
->collide
) return false;
289 if(!m
->bih
&& !m
->setBIH()) return false;
290 if(!maxdist
) maxdist
= 1e16f
;
293 float yaw
= -180.0f
-(float)((e
.attr1
+7)-(e
.attr1
+7)%15);
295 if(yaw
!= 0) yawray(yo
, yray
, yaw
);
296 return m
->bih
->traverse(yo
, yray
, maxdist
, dist
, mode
);