2014-01-31 08:23:00 +13:00
|
|
|
|
2019-01-18 15:55:06 +01:00
|
|
|
#include "std.hpp"
|
2014-01-31 08:23:00 +13:00
|
|
|
#include <queue>
|
2019-01-18 15:55:06 +01:00
|
|
|
#include "world.hpp"
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//0=tris compared for collision
|
|
|
|
|
//1=max proj err of terrain
|
|
|
|
|
float stats3d[10];
|
|
|
|
|
|
|
|
|
|
extern gxScene *gx_scene;
|
|
|
|
|
extern gxRuntime *gx_runtime;
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
static std::list<Object*> s_objectsEnabled, s_objectsVisible;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
static void StaticEnumerateEnabled() {
|
|
|
|
|
s_objectsEnabled.clear();
|
|
|
|
|
for (Entity *e = Entity::GetEntityOrphans(); e; e = e->GetSuccessor()) {
|
|
|
|
|
e->EnumerateEnabled(s_objectsEnabled);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
static void StaticEnumerateVisible() {
|
|
|
|
|
s_objectsVisible.clear();
|
|
|
|
|
for (Entity *e = Entity::GetEntityOrphans(); e; e = e->GetSuccessor()) {
|
|
|
|
|
e->EnumerateVisible(s_objectsVisible);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************* Update *******************************/
|
|
|
|
|
|
|
|
|
|
static vector<Object*> _objsByType[1000];
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
static vector<ObjCollision*> free_colls, used_colls;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
static ObjCollision *allocObjColl(Object *with, const Vector &coords, const Collision &coll) {
|
2014-01-31 08:23:00 +13:00
|
|
|
ObjCollision *c;
|
2017-04-09 05:35:18 +02:00
|
|
|
if (free_colls.size()) {
|
|
|
|
|
c = free_colls.back();
|
2014-01-31 08:23:00 +13:00
|
|
|
free_colls.pop_back();
|
2017-04-09 05:35:18 +02:00
|
|
|
} else {
|
|
|
|
|
c = new ObjCollision();
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2017-04-09 05:35:18 +02:00
|
|
|
used_colls.push_back(c);
|
|
|
|
|
c->with = with;
|
|
|
|
|
c->coords = coords;
|
|
|
|
|
c->collision = coll;
|
2014-01-31 08:23:00 +13:00
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
static void collided(Object *src, Object *dest, const Line &line, const Collision &coll, float y_scale) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
ObjCollision *c;
|
2017-04-09 05:35:18 +02:00
|
|
|
const Vector &coords = line*coll.time - coll.normal*src->getCollisionRadii().x;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
c = allocObjColl(dest, coords, coll);
|
|
|
|
|
c->coords.y *= y_scale;
|
|
|
|
|
src->addCollision(c);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
c = allocObjColl(src, coords, coll);
|
|
|
|
|
c->coords.y *= y_scale;
|
|
|
|
|
dest->addCollision(c);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
void World::clearCollisions() {
|
|
|
|
|
for (int k = 0; k < 1000; ++k) {
|
2014-01-31 08:23:00 +13:00
|
|
|
_collInfo[k].clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
void World::addCollision(int src_type, int dst_type, int method, int response) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
vector<CollInfo> &info = _collInfo[src_type];
|
|
|
|
|
for (size_t k = 0; k < info.size(); ++k) {
|
|
|
|
|
const CollInfo &t = info[k];
|
|
|
|
|
if (dst_type == t.dst_type) return;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
CollInfo co = { dst_type,method,response };
|
2014-01-31 08:23:00 +13:00
|
|
|
_collInfo[src_type].push_back(co);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
bool World::hitTest(const Line &line, float radius, Object *obj, const Transform &tf, int method, Collision *curr_coll) {
|
|
|
|
|
switch (method) {
|
|
|
|
|
case COLLISION_METHOD_SPHERE:
|
|
|
|
|
return curr_coll->sphereCollide(line, radius, tf.v, obj->getCollisionRadii().x);
|
|
|
|
|
case COLLISION_METHOD_POLYGON:
|
|
|
|
|
return obj->collide(line, radius, curr_coll, tf);
|
|
|
|
|
case COLLISION_METHOD_BOX:
|
|
|
|
|
Transform t = tf;
|
|
|
|
|
t.m.i.normalize(); t.m.j.normalize(); t.m.k.normalize();
|
|
|
|
|
if (curr_coll->boxCollide(~t*line, radius, obj->getCollisionBox())) {
|
|
|
|
|
curr_coll->normal = t.m*curr_coll->normal;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
bool World::CheckLineOfSight(Object *src, Object *dest) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
StaticEnumerateEnabled();
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
Object *coll_obj = 0;
|
2014-01-31 08:23:00 +13:00
|
|
|
Collision curr_coll;
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
Line line(src->GetWorldPosition(), dest->GetWorldPosition() - src->GetWorldPosition());
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (Object* obj : s_objectsEnabled) {
|
|
|
|
|
if (obj == src || obj == dest || !obj->getPickGeometry() || !obj->getObscurer()) continue;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (hitTest(line, 0, obj, obj->GetWorldTransform(), obj->getPickGeometry(), &curr_coll)) {
|
2014-01-31 08:23:00 +13:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
Object *World::traceRay(const Line &line, float radius, ObjCollision *curr_coll) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
StaticEnumerateEnabled();
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
Object *coll_obj = 0;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (Object* obj : s_objectsEnabled) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (!obj->getPickGeometry()) continue;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (hitTest(line, radius, obj, obj->GetWorldTransform(), obj->getPickGeometry(), &curr_coll->collision)) {
|
|
|
|
|
coll_obj = obj;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
2017-04-09 05:35:18 +02:00
|
|
|
if (curr_coll->with = coll_obj) {
|
|
|
|
|
curr_coll->coords = line*curr_coll->collision.time - curr_coll->collision.normal*radius;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
return coll_obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// NEW VERSION
|
|
|
|
|
//
|
2017-04-09 05:35:18 +02:00
|
|
|
void World::collide(Object *src) {
|
|
|
|
|
Vector dv = src->GetWorldTransform().v;
|
|
|
|
|
Vector sv = src->getPrevWorldTform().v;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (sv == dv) {
|
|
|
|
|
if (dv.x != sv.x || dv.y != sv.y || dv.z != sv.z) {
|
|
|
|
|
src->SetWorldPosition(sv);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
Vector panic = sv;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
static Transform y_tform;
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
const Vector &radii = src->getCollisionRadii();
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
float radius = radii.x, inv_y_scale;
|
|
|
|
|
float y_scale = inv_y_scale = y_tform.m.j.y = 1;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (radii.x != radii.y) {
|
|
|
|
|
y_scale = y_tform.m.j.y = radius / radii.y;
|
|
|
|
|
inv_y_scale = 1 / y_scale;
|
|
|
|
|
sv.y *= y_scale;
|
|
|
|
|
dv.y *= y_scale;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
int n_hit = 0;
|
2014-01-31 08:23:00 +13:00
|
|
|
Plane planes[2];
|
2017-04-09 05:35:18 +02:00
|
|
|
Line coll_line(sv, dv - sv);
|
|
|
|
|
Vector dir = coll_line.d;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
float td = coll_line.d.length();
|
|
|
|
|
float td_xz = Vector(coll_line.d.x, 0, coll_line.d.z).length();
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
const vector<CollInfo> &collinfos = _collInfo[src->getCollisionType()];
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
int hits = 0;
|
|
|
|
|
for (;;) {
|
2014-01-31 08:23:00 +13:00
|
|
|
Collision coll;
|
2017-04-09 05:35:18 +02:00
|
|
|
Object *coll_obj = 0;
|
|
|
|
|
vector<CollInfo>::const_iterator coll_it, coll_info;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (coll_it = collinfos.begin(); coll_it != collinfos.end(); ++coll_it) {
|
|
|
|
|
// const std::list<Object*> &dst_objs = _objsByType[coll_it->dst_type];
|
|
|
|
|
for (Object* dst : /*dst_objs*/_objsByType[coll_it->dst_type]) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (src == dst) continue;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
const Transform &dst_tform = dst->getPrevWorldTform();
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (y_scale == 1) {
|
|
|
|
|
if (hitTest(
|
|
|
|
|
coll_line, radius, dst, dst_tform,
|
|
|
|
|
coll_it->method, &coll)) {
|
|
|
|
|
coll_obj = dst;
|
|
|
|
|
coll_info = coll_it;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2017-04-09 05:35:18 +02:00
|
|
|
} else {
|
|
|
|
|
if (hitTest(
|
|
|
|
|
coll_line, radius, dst, y_tform * dst_tform,
|
|
|
|
|
coll_it->method, &coll)) {
|
|
|
|
|
coll_obj = dst;
|
|
|
|
|
coll_info = coll_it;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-09 05:35:18 +02:00
|
|
|
if (!coll_obj) break;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//register collision
|
2017-04-09 05:35:18 +02:00
|
|
|
if (++hits == WORLD_COLLISION_HITS) {
|
2014-01-31 08:23:00 +13:00
|
|
|
// exit(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
collided(src, coll_obj, coll_line, coll, inv_y_scale);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
Plane coll_plane(coll_line*coll.time, coll.normal);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
coll_plane.d -= COLLISION_FLT_EPSILON;
|
|
|
|
|
coll.time = coll_plane.t_intersect(coll_line);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (coll.time > 0) {// && fabs(coll.normal.dot( coll_line.d ))>FLT_EPSILON ){
|
2014-01-31 08:23:00 +13:00
|
|
|
//update source position - ONLY IF AHEAD!
|
2017-04-09 05:35:18 +02:00
|
|
|
sv = coll_line*coll.time;
|
|
|
|
|
td *= 1 - coll.time;
|
|
|
|
|
td_xz *= 1 - coll.time;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (coll_info->response == COLLISION_RESPONSE_STOP) {
|
|
|
|
|
dv = sv;
|
2014-01-31 08:23:00 +13:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//find nearest point on plane to dest
|
2017-04-09 05:35:18 +02:00
|
|
|
Vector nv = coll_plane.nearest(dv);
|
|
|
|
|
|
|
|
|
|
if (n_hit == 0) {
|
|
|
|
|
dv = nv;
|
|
|
|
|
} else if (n_hit == 1) {
|
|
|
|
|
if (planes[0].distance(nv) >= 0) {
|
|
|
|
|
dv = nv; n_hit = 0;
|
|
|
|
|
} else if (fabs(planes[0].n.dot(coll_plane.n)) < 1 - FLT_EPSILON) {
|
|
|
|
|
dv = coll_plane.intersect(planes[0]).nearest(dv);
|
|
|
|
|
} else {
|
2014-01-31 08:23:00 +13:00
|
|
|
//SQUISHED!
|
|
|
|
|
//exit(0);
|
2017-04-09 05:35:18 +02:00
|
|
|
hits = WORLD_COLLISION_HITS; break;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2017-04-09 05:35:18 +02:00
|
|
|
} else if (planes[0].distance(nv) >= 0 && planes[1].distance(nv) >= 0) {
|
|
|
|
|
dv = nv; n_hit = 0;
|
|
|
|
|
} else {
|
|
|
|
|
dv = sv; break;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
Vector dd(dv - sv);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//going behind initial direction? really necessary?
|
2017-04-09 05:35:18 +02:00
|
|
|
if (dd.dot(dir) <= 0) { dv = sv; break; }
|
|
|
|
|
|
|
|
|
|
if (coll_info->response == COLLISION_RESPONSE_SLIDE) {
|
|
|
|
|
float d = dd.length();
|
|
|
|
|
if (d <= FLT_EPSILON) { dv = sv; break; }
|
|
|
|
|
if (d > td) dd *= td / d;
|
|
|
|
|
} else if (coll_info->response == COLLISION_RESPONSE_SLIDEXZ) {
|
|
|
|
|
float d = Vector(dd.x, 0, dd.z).length();
|
|
|
|
|
if (d <= FLT_EPSILON) { dv = sv; break; }
|
|
|
|
|
if (d > td_xz) dd *= td_xz / d;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
coll_line.o = sv;
|
|
|
|
|
coll_line.d = dd; dv = sv + dd;
|
|
|
|
|
planes[n_hit++] = coll_plane;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (hits) {
|
|
|
|
|
if (hits < WORLD_COLLISION_HITS) {
|
|
|
|
|
dv.y *= inv_y_scale;
|
|
|
|
|
src->SetWorldPosition(dv);
|
|
|
|
|
} else {
|
|
|
|
|
src->SetWorldPosition(panic);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
//
|
|
|
|
|
// OLD VERSION
|
|
|
|
|
//
|
|
|
|
|
void World::collide( Object *src ){
|
|
|
|
|
|
|
|
|
|
static const int MAX_HITS=100;
|
|
|
|
|
|
|
|
|
|
Vector dv=src->getWorldTform().v;
|
|
|
|
|
Vector sv=src->getPrevWorldTform().v;
|
|
|
|
|
|
|
|
|
|
if( sv==dv ){
|
|
|
|
|
if( dv.x!=sv.x || dv.y!=sv.y || dv.z!=sv.z ){
|
|
|
|
|
src->setWorldPosition( sv );
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vector panic=sv;
|
|
|
|
|
|
|
|
|
|
static Transform y_tform;
|
|
|
|
|
|
|
|
|
|
const Vector &radii=src->getCollisionRadii();
|
|
|
|
|
|
|
|
|
|
float radius=radii.x,inv_y_scale;
|
|
|
|
|
float y_scale=inv_y_scale=y_tform.m.j.y=1;
|
|
|
|
|
|
|
|
|
|
if( radii.x!=radii.y ){
|
|
|
|
|
y_scale=y_tform.m.j.y=radius/radii.y;
|
|
|
|
|
inv_y_scale=1/y_scale;
|
|
|
|
|
sv.y*=y_scale;
|
|
|
|
|
dv.y*=y_scale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int n_hit=0;
|
|
|
|
|
Plane planes[2];
|
|
|
|
|
Line coll_line( sv,dv-sv );
|
|
|
|
|
Vector dir=coll_line.d;
|
|
|
|
|
|
|
|
|
|
float td=coll_line.d.length();
|
|
|
|
|
float td_xz=Vector( coll_line.d.x,0,coll_line.d.z ).length();
|
|
|
|
|
|
|
|
|
|
const vector<CollInfo> &collinfos=_collInfo[src->getCollisionType()];
|
|
|
|
|
|
|
|
|
|
int hits=0;
|
|
|
|
|
while( hits<MAX_HITS ){
|
|
|
|
|
|
|
|
|
|
Collision coll;
|
|
|
|
|
Object *coll_obj=0;
|
|
|
|
|
vector<CollInfo>::const_iterator coll_it,coll_info;
|
|
|
|
|
|
|
|
|
|
for( coll_it=collinfos.begin();coll_it!=collinfos.end();++coll_it ){
|
|
|
|
|
|
|
|
|
|
vector<Object*>::const_iterator dst_it;
|
2017-04-09 05:35:18 +02:00
|
|
|
|
2014-01-31 08:23:00 +13:00
|
|
|
const vector<Object*> &dst_objs=_objsByType[coll_it->dst_type];
|
|
|
|
|
|
|
|
|
|
for( dst_it=dst_objs.begin();dst_it!=dst_objs.end();++dst_it ){
|
|
|
|
|
|
|
|
|
|
Object *dst=*dst_it;
|
|
|
|
|
|
|
|
|
|
if( src==dst ) continue;
|
|
|
|
|
|
|
|
|
|
const Transform &dst_tform=dst->getPrevWorldTform();
|
|
|
|
|
|
|
|
|
|
if( y_scale==1 ){
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if( hitTest(
|
2014-01-31 08:23:00 +13:00
|
|
|
coll_line,radius,dst,dst_tform,
|
|
|
|
|
coll_it->method,&coll ) ){
|
|
|
|
|
coll_obj=dst;
|
|
|
|
|
coll_info=coll_it;
|
|
|
|
|
}
|
|
|
|
|
}else{
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if( hitTest(
|
2014-01-31 08:23:00 +13:00
|
|
|
coll_line,radius,dst,y_tform * dst_tform,
|
|
|
|
|
coll_it->method,&coll ) ){
|
|
|
|
|
coll_obj=dst;
|
|
|
|
|
coll_info=coll_it;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( !coll_obj ) break;
|
|
|
|
|
|
|
|
|
|
//register collision
|
|
|
|
|
++hits;
|
|
|
|
|
collided( src,coll_obj,coll_line,coll,inv_y_scale );
|
|
|
|
|
|
|
|
|
|
//create collision plane
|
|
|
|
|
Plane coll_plane( coll_line*coll.time,coll.normal );
|
|
|
|
|
|
|
|
|
|
//move plane out a bit (cough)
|
|
|
|
|
coll_plane.d-=.001f;
|
|
|
|
|
|
2016-05-04 09:58:44 +02:00
|
|
|
if( fabs(coll.normal.dot( coll_line.d ))>FLT_EPSILON ){
|
2014-01-31 08:23:00 +13:00
|
|
|
float t=coll_plane.t_intersect( coll_line );
|
|
|
|
|
//update source position - ONLY IF AHEAD!
|
|
|
|
|
if( t>0 ){
|
|
|
|
|
sv=coll_line*t;
|
|
|
|
|
td*=1-coll.time;
|
|
|
|
|
td_xz*=1-coll.time;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//STOP?
|
|
|
|
|
if( coll_info->response==COLLISION_RESPONSE_STOP ){
|
|
|
|
|
dv=sv;
|
2017-04-09 05:35:18 +02:00
|
|
|
break;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//find nearest point on plane to dest
|
|
|
|
|
Vector nv=coll_plane.nearest( dv );
|
|
|
|
|
|
|
|
|
|
//SLIDE!
|
|
|
|
|
if( n_hit==0 ){
|
|
|
|
|
dv=nv;
|
|
|
|
|
}else if( n_hit==1 ){
|
|
|
|
|
if( planes[0].distance(nv)>=0 ){
|
|
|
|
|
dv=nv;n_hit=0;
|
2016-05-04 09:58:44 +02:00
|
|
|
}else if( fabs( planes[0].n.dot( coll_plane.n ) )<1-FLT_EPSILON ){
|
2014-01-31 08:23:00 +13:00
|
|
|
dv=coll_plane.intersect( planes[0] ).nearest( dv );
|
|
|
|
|
}else{
|
|
|
|
|
hits=MAX_HITS;break;
|
|
|
|
|
}
|
|
|
|
|
}else if( planes[0].distance(nv)>=0 && planes[1].distance(nv)>=0 ){
|
|
|
|
|
dv=nv;n_hit=0;
|
|
|
|
|
}else{
|
|
|
|
|
dv=sv;break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vector dd( dv-sv );
|
|
|
|
|
|
|
|
|
|
//going behind initial direction? really necessary?
|
|
|
|
|
if( dd.dot( dir )<=0 ){ dv=sv;break; }
|
|
|
|
|
|
|
|
|
|
if( coll_info->response==COLLISION_RESPONSE_SLIDE ){
|
|
|
|
|
float d=dd.length();
|
2016-05-04 09:58:44 +02:00
|
|
|
if( d<=FLT_EPSILON ){ dv=sv;break; }
|
2014-01-31 08:23:00 +13:00
|
|
|
if( d>td ) dd*=td/d;
|
|
|
|
|
}else if( coll_info->response==COLLISION_RESPONSE_SLIDEXZ ){
|
|
|
|
|
float d=Vector( dd.x,0,dd.z ).length();
|
2016-05-04 09:58:44 +02:00
|
|
|
if( d<=FLT_EPSILON ){ dv=sv;break; }
|
2014-01-31 08:23:00 +13:00
|
|
|
if( d>td_xz ) dd*=td_xz/d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
coll_line.o=sv;
|
|
|
|
|
coll_line.d=dd;dv=sv+dd;
|
|
|
|
|
planes[n_hit++]=coll_plane;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( hits ){
|
|
|
|
|
if( hits<MAX_HITS ){
|
|
|
|
|
dv.y*=inv_y_scale;
|
|
|
|
|
src->setWorldPosition( dv );
|
|
|
|
|
}else{
|
|
|
|
|
src->setWorldPosition( panic );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
void World::update(float elapsed) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
stats3d[0] = 0;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (; used_colls.size(); used_colls.pop_back()) {
|
|
|
|
|
free_colls.push_back(used_colls.back());
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
StaticEnumerateEnabled();
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (Object* o : s_objectsEnabled) {
|
|
|
|
|
if (int n = o->getCollisionType()) {
|
|
|
|
|
_objsByTypeSwappable[n].push_back(o);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
o->beginUpdate(elapsed);
|
|
|
|
|
if (o->getCollisionType()) collide(o);
|
2014-01-31 08:23:00 +13:00
|
|
|
o->endUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (int k = 0; k < WORLD_COLLISION_TYPES; ++k) {
|
|
|
|
|
_objsByTypeSwappable[k].swap(_objsByType[k]);
|
|
|
|
|
_objsByTypeSwappable[k].clear();
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************** Render *********************************/
|
|
|
|
|
|
|
|
|
|
static Transform cam_tform; //current camera transform
|
|
|
|
|
|
|
|
|
|
static vector<gxLight*> _lights;
|
|
|
|
|
static vector<Mirror*> _mirrors;
|
|
|
|
|
static vector<Listener*> _listeners;
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
struct OrderComp {
|
|
|
|
|
bool operator()(Object *a, Object *b) {
|
|
|
|
|
return a->getOrder() < b->getOrder();
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
struct TransComp {
|
|
|
|
|
bool operator()(Model *a, Model *b)const {
|
|
|
|
|
return
|
|
|
|
|
cam_tform.v.distance(a->getRenderTform().v) <
|
|
|
|
|
cam_tform.v.distance(b->getRenderTform().v);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
static vector<Model*> ord_mods, unord_mods;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
static priority_queue<Model*, vector<Model*>, OrderComp> ord_que;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
static priority_queue<Camera*, vector<Camera*>, OrderComp> cam_que;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
static priority_queue<Model*, vector<Model*>, TransComp> transparents;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
void World::capture() {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
StaticEnumerateVisible();
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (Object* o : s_objectsVisible) {
|
|
|
|
|
o->capture();
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
void World::render(float tween) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//set render tweens, and build ordered and unordered model lists...
|
|
|
|
|
ord_mods.clear();
|
|
|
|
|
unord_mods.clear();
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
s_objectsVisible.clear();
|
2014-01-31 08:23:00 +13:00
|
|
|
_lights.clear();
|
|
|
|
|
_mirrors.clear();
|
|
|
|
|
_listeners.clear();
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
StaticEnumerateVisible();
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (Object* o : s_objectsVisible) {
|
|
|
|
|
if (!o->beginRender(tween)) continue;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (Light *t = o->getLight()) _lights.push_back(t->getGxLight());
|
|
|
|
|
else if (Camera *t = o->getCamera()) cam_que.push(t);
|
|
|
|
|
else if (Mirror *t = o->getMirror()) _mirrors.push_back(t);
|
|
|
|
|
else if (Listener *t = o->getListener()) _listeners.push_back(t);
|
|
|
|
|
else if (Model *t = o->getModel()) {
|
|
|
|
|
if (t->getOrder()) ord_que.push(t);
|
|
|
|
|
else unord_mods.push_back(t);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (; ord_que.size(); ord_que.pop()) ord_mods.push_back(ord_que.top());
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
// gx_runtime->debugLog( "RenderWorld" );
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (!gx_scene->begin(_lights)) return;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (; cam_que.size(); cam_que.pop()) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
Camera *cam = cam_que.top();
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (!cam->beginRenderFrame()) continue;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
vector<Mirror*>::const_iterator mir_it;
|
2017-04-09 05:35:18 +02:00
|
|
|
for (mir_it = _mirrors.begin(); mir_it != _mirrors.end(); ++mir_it) {
|
|
|
|
|
render(cam, *mir_it);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
render(cam, 0);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gx_scene->end();
|
|
|
|
|
|
|
|
|
|
// gx_runtime->debugLog( "End RenderWorld" );
|
|
|
|
|
|
|
|
|
|
vector<Listener*>::const_iterator lis_it;
|
2017-04-09 05:35:18 +02:00
|
|
|
for (lis_it = _listeners.begin(); lis_it != _listeners.end(); ++lis_it) {
|
2014-01-31 08:23:00 +13:00
|
|
|
(*lis_it)->renderListener();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
void World::render(Camera *cam, Mirror *mirror) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (mirror) {
|
|
|
|
|
const Transform &t = mirror->getRenderTform();
|
|
|
|
|
cam_tform = t * Transform(scaleMatrix(1, -1, 1)) * -t * cam->getRenderTform();
|
|
|
|
|
gx_scene->setFlippedTris(true);
|
|
|
|
|
} else {
|
|
|
|
|
cam_tform = cam->getRenderTform();
|
|
|
|
|
gx_scene->setFlippedTris(false);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//set camera matrix
|
2017-04-09 05:35:18 +02:00
|
|
|
gx_scene->setViewMatrix((gxScene::Matrix*)&(-cam_tform));
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//initialize render context
|
2017-04-09 05:35:18 +02:00
|
|
|
RenderContext rc(cam_tform, cam->getFrustum(), mirror != 0);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//draw everything in order
|
2017-04-09 05:35:18 +02:00
|
|
|
size_t ord = 0;
|
|
|
|
|
gx_scene->setZMode(gxScene::ZMODE_DISABLE);
|
|
|
|
|
while (ord < ord_mods.size() && ord_mods[ord]->getOrder()>0) {
|
|
|
|
|
Model *mod = ord_mods[ord++];
|
|
|
|
|
if (!mod->doAutoFade(cam_tform.v)) continue;
|
|
|
|
|
render(mod, rc);
|
2014-01-31 08:23:00 +13:00
|
|
|
flushTransparent();
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
gx_scene->setZMode(gxScene::ZMODE_NORMAL);
|
|
|
|
|
for (size_t k = 0; k < unord_mods.size(); ++k) {
|
|
|
|
|
Model *mod = unord_mods[k];
|
|
|
|
|
if (!mod->doAutoFade(cam_tform.v)) continue;
|
|
|
|
|
render(mod, rc);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2017-04-09 05:35:18 +02:00
|
|
|
gx_scene->setZMode(gxScene::ZMODE_CMPONLY);
|
2014-01-31 08:23:00 +13:00
|
|
|
flushTransparent();
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
gx_scene->setZMode(gxScene::ZMODE_DISABLE);
|
|
|
|
|
while (ord < ord_mods.size()) {
|
|
|
|
|
Model *mod = ord_mods[ord++];
|
|
|
|
|
if (!mod->doAutoFade(cam_tform.v)) continue;
|
|
|
|
|
render(mod, rc);
|
2014-01-31 08:23:00 +13:00
|
|
|
flushTransparent();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
void World::render(Model *mod, const RenderContext &rc) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
bool trans = mod->render(rc);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (mod->queueSize(Model::QUEUE_OPAQUE)) {
|
|
|
|
|
if (mod->getRenderSpace() == Model::RENDER_SPACE_LOCAL) {
|
|
|
|
|
gx_scene->setWorldMatrix((gxScene::Matrix*)&mod->getRenderTform());
|
|
|
|
|
} else {
|
|
|
|
|
gx_scene->setWorldMatrix(0);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2017-04-09 05:35:18 +02:00
|
|
|
mod->renderQueue(Model::QUEUE_OPAQUE);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
if (trans || mod->queueSize(Model::QUEUE_TRANSPARENT)) {
|
|
|
|
|
transparents.push(mod);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
void World::flushTransparent() {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
bool local = true;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2017-04-09 05:35:18 +02:00
|
|
|
for (; transparents.size(); transparents.pop()) {
|
|
|
|
|
Model *mod = transparents.top();
|
|
|
|
|
if (mod->getRenderSpace() == Model::RENDER_SPACE_LOCAL) {
|
|
|
|
|
gx_scene->setWorldMatrix((gxScene::Matrix*)&mod->getRenderTform());
|
|
|
|
|
local = true;
|
|
|
|
|
} else if (local) {
|
|
|
|
|
gx_scene->setWorldMatrix(0);
|
|
|
|
|
local = false;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2017-04-09 05:35:18 +02:00
|
|
|
mod->renderQueue(Model::QUEUE_TRANSPARENT);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|