4
struct SphereBranch : SphereTree
6
SphereTree *child1, *child2;
8
SphereBranch(SphereTree *c1, SphereTree *c2) : child1(c1), child2(c2)
10
vec n(child2->center);
11
n.sub(child1->center);
12
float dist = n.magnitude();
14
radius = (child1->radius + child2->radius + dist) / 2;
16
center = child1->center;
19
n.mul((radius - child1->radius) / dist);
30
bool childintersect(const vec &o, const vec &ray, float maxdist, float &dist, int mode) const
32
return child1->intersect(o, ray, maxdist, dist, mode) ||
33
child2->intersect(o, ray, maxdist, dist, mode);
37
struct SphereLeaf : SphereTree
41
SphereLeaf(const SphereTree::tri &t) : tri(t)
47
float r1 = center.dist(t.a),
48
r2 = center.dist(t.b),
49
r3 = center.dist(t.c);
50
radius = max(r1, max(r2, r3));
53
bool childintersect(const vec &o, const vec &ray, float maxdist, float &dist, int mode) const
55
vec edge1(tri.b), edge2(tri.c);
60
float det = edge1.dot(p);
61
if(det == 0) return false;
64
float u = r.dot(p) / det;
65
if(u < 0 || u > 1) return false;
68
float v = ray.dot(q) / det;
69
if(v < 0 || u + v > 1) return false;
70
float f = edge2.dot(q) / det;
71
if(f < 0 || f > maxdist) return false;
72
if(tri.tex && (mode&RAY_ALPHAPOLY)==RAY_ALPHAPOLY)
74
if(!tri.tex->alphamask)
76
loadalphamask(tri.tex);
77
if(!tri.tex->alphamask) { dist = f; return true; }
79
float s = tri.tc[0] + u*(tri.tc[2] - tri.tc[0]) + v*(tri.tc[4] - tri.tc[0]),
80
t = tri.tc[1] + u*(tri.tc[3] - tri.tc[1]) + v*(tri.tc[5] - tri.tc[1]);
81
int si = int(s*tri.tex->w), ti = int(t*tri.tex->h);
82
if(!(tri.tex->alphamask[ti*((tri.tex->w+7)/8) + si/8] & (1<<(si%8)))) return false;
88
bool isleaf() { return true; }
91
SphereTree *buildspheretree(int numtris, const SphereTree::tri *tris)
93
if(numtris<=0) return NULL;
95
SphereTree **spheres = new SphereTree *[numtris];
96
loopi(numtris) spheres[i] = new SphereLeaf(tris[i]);
98
vec center = vec(0, 0, 0);
99
loopi(numtris) center.add(spheres[i]->center);
102
int numspheres = numtris;
109
float d = center.dist(spheres[i]->center) - spheres[i]->radius;
116
SphereTree *child1 = spheres[farthest];
118
float radius = 1e16f;
121
if(i==farthest) continue;
122
SphereTree *child2 = spheres[i];
123
float xyradius = (child1->radius + child2->radius + child1->center.dist(child2->center)) / 2;
124
if(!xyradius && child1->isleaf() && child2->isleaf() && ((SphereLeaf *)child1)->tri == ((SphereLeaf *)child2)->tri)
126
spheres[i] = spheres[--numspheres];
127
if(farthest==numspheres) farthest = i;
131
else if(xyradius < radius)
139
spheres[farthest] = new SphereBranch(spheres[farthest], spheres[closest]);
140
spheres[closest] = spheres[--numspheres];
144
SphereTree *root = spheres[0];
149
static inline void yawray(vec &o, vec &ray, float angle)
152
float c = cosf(angle), s = sinf(angle),
154
rx = ox+ray.x, ry = oy+ray.y;
157
ray.x = rx*c - ry*s - o.x;
158
ray.y = ry*c + rx*s - o.y;
162
bool mmintersect(const extentity &e, const vec &o, const vec &ray, float maxdist, int mode, float &dist)
164
model *m = loadmodel(NULL, e.attr2);
168
if(!m->shadow || checktriggertype(e.attr3, TRIG_COLLIDE|TRIG_DISAPPEAR)) return false;
170
else if((mode&RAY_ENTS)!=RAY_ENTS && !m->collide) return false;
171
if(!m->spheretree && !m->setspheretree()) return false;
172
if(!maxdist) maxdist = 1e16f;
175
if(!m->spheretree->shellintersect(yo, ray, maxdist)) return false;
176
float yaw = -180.0f-(float)((e.attr1+7)-(e.attr1+7)%15);
178
if(yaw != 0) yawray(yo, yray, yaw);
179
return m->spheretree->childintersect(yo, yray, maxdist, dist, mode);