mirror of
https://github.com/XProger/OpenLara.git
synced 2025-02-25 16:03:31 +01:00
This commit is contained in:
parent
9ac30862c7
commit
fab5d8b301
@ -402,6 +402,10 @@ struct Controller {
|
||||
return mask;
|
||||
}
|
||||
|
||||
bool collide(const Sphere &sphere) {
|
||||
return getBoundingBoxLocal().intersect(Sphere(getMatrix().inverse() * sphere.center, sphere.radius));
|
||||
}
|
||||
|
||||
vec3 trace(int fromRoom, const vec3 &from, const vec3 &to, int &room, bool isCamera) { // TODO: use Bresenham
|
||||
room = fromRoom;
|
||||
|
||||
|
@ -668,9 +668,12 @@ namespace Debug {
|
||||
level.getFloorInfo(((Controller*)entity.controller)->getRoomIndex(), entity.x, entity.y, entity.z, info);
|
||||
sprintf(buf, "floor = %d, roomBelow = %d, roomAbove = %d, height = %d", info.floorIndex, info.roomBelow, info.roomAbove, info.floor - info.ceiling);
|
||||
Debug::Draw::text(vec2(16, y += 16), vec4(1.0f), buf);
|
||||
|
||||
|
||||
y += 16;
|
||||
if (info.lava)
|
||||
Debug::Draw::text(vec2(16, y += 16), vec4(1.0f, 0.5f, 0.3f, 1.0f), "LAVA");
|
||||
|
||||
if (info.trigCmdCount > 0) {
|
||||
y += 16;
|
||||
sprintf(buf, "trigger: %s%s mask: %d timer: %d", getTriggerType(level, info.trigger), info.trigInfo.once ? " (once)" : "", info.trigInfo.mask, info.trigInfo.timer);
|
||||
Debug::Draw::text(vec2(16, y += 16), vec4(0.5f, 0.8f, 0.5f, 1.0f), buf);
|
||||
|
||||
|
32
src/format.h
32
src/format.h
@ -51,7 +51,7 @@
|
||||
E( TRAP_SPIKES ) \
|
||||
E( TRAP_BOULDER ) \
|
||||
E( TRAP_DART ) \
|
||||
E( TRAP_DARTGUN ) \
|
||||
E( TRAP_DART_EMITTER ) \
|
||||
E( DRAWBRIDGE ) \
|
||||
E( TRAP_SLAM ) \
|
||||
E( TRAP_SWORD ) \
|
||||
@ -187,10 +187,10 @@
|
||||
E( MUTANT_GRENADE ) \
|
||||
E( UNUSED_16 ) \
|
||||
E( UNUSED_17 ) \
|
||||
E( LAVA_PARTICLE ) \
|
||||
E( LAVA_EMITTER ) \
|
||||
E( FLAME ) \
|
||||
E( FLAME_EMITTER ) \
|
||||
E( TRAP_LAVA_PARTICLE ) \
|
||||
E( TRAP_LAVA_EMITTER ) \
|
||||
E( TRAP_FLAME ) \
|
||||
E( TRAP_FLAME_EMITTER ) \
|
||||
E( TRAP_LAVA ) \
|
||||
E( MUTANT_EGG_BIG ) \
|
||||
E( BOAT ) \
|
||||
@ -268,12 +268,16 @@ namespace TR {
|
||||
|
||||
SND_UNDERWATER = 60,
|
||||
|
||||
SND_BOULDER = 70,
|
||||
|
||||
SND_FLOOD = 81,
|
||||
|
||||
SND_HIT_LION = 85,
|
||||
|
||||
SND_HIT_RAT = 95,
|
||||
|
||||
SND_ROCK = 99,
|
||||
|
||||
SND_EXPLOSION = 104,
|
||||
|
||||
SND_INV_SPIN = 108,
|
||||
@ -291,7 +295,9 @@ namespace TR {
|
||||
SND_HIT_SKATEBOY = 132,
|
||||
|
||||
SND_HIT_MUTANT = 142,
|
||||
|
||||
SND_STOMP = 147,
|
||||
|
||||
SND_FLAME = 150,
|
||||
SND_DART = 151,
|
||||
|
||||
SND_TNT = 170,
|
||||
@ -327,7 +333,7 @@ namespace TR {
|
||||
HIT_BLADE,
|
||||
HIT_BOULDER,
|
||||
HIT_SPIKES,
|
||||
HIT_FLAME,
|
||||
HIT_LAVA,
|
||||
HIT_SLAM,
|
||||
HIT_REX,
|
||||
};
|
||||
@ -578,7 +584,7 @@ namespace TR {
|
||||
FLOOR ,
|
||||
CEILING ,
|
||||
TRIGGER ,
|
||||
KILL ,
|
||||
LAVA ,
|
||||
};
|
||||
};
|
||||
|
||||
@ -663,7 +669,7 @@ namespace TR {
|
||||
return (type >= PISTOLS && type <= AMMO_UZIS) ||
|
||||
(type >= PUZZLE_1 && type <= PUZZLE_4) ||
|
||||
(type >= KEY_ITEM_1 && type <= KEY_ITEM_4) ||
|
||||
(type == MEDIKIT_SMALL || type == MEDIKIT_BIG || type == SCION_1); // TODO: recheck all items
|
||||
(type == MEDIKIT_SMALL || type == MEDIKIT_BIG || type == SCION_1 || type == LEADBAR); // TODO: recheck all items
|
||||
}
|
||||
|
||||
bool isActor() const {
|
||||
@ -1140,7 +1146,7 @@ namespace TR {
|
||||
int slantX, slantZ;
|
||||
int floorIndex;
|
||||
int boxIndex;
|
||||
int kill;
|
||||
int lava;
|
||||
int trigCmdCount;
|
||||
Trigger trigger;
|
||||
FloorData::TriggerInfo trigInfo;
|
||||
@ -2172,7 +2178,7 @@ namespace TR {
|
||||
info.roomAbove = s.roomAbove;
|
||||
info.floorIndex = s.floorIndex;
|
||||
info.boxIndex = s.boxIndex;
|
||||
info.kill = 0;
|
||||
info.lava = false;
|
||||
info.trigger = Trigger::ACTIVATE;
|
||||
info.trigCmdCount = 0;
|
||||
|
||||
@ -2344,8 +2350,8 @@ namespace TR {
|
||||
break;
|
||||
}
|
||||
|
||||
case FloorData::KILL :
|
||||
info.kill = 1;
|
||||
case FloorData::LAVA :
|
||||
info.lava = true;
|
||||
break;
|
||||
|
||||
default : LOG("unknown func: %d\n", cmd.func);
|
||||
|
54
src/lara.h
54
src/lara.h
@ -400,14 +400,6 @@ struct Lara : Character {
|
||||
} *braid;
|
||||
|
||||
Lara(IGame *game, int entity) : Character(game, entity, LARA_MAX_HEALTH), dozy(false), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), braid(NULL) {
|
||||
|
||||
if (getEntity().type == TR::Entity::LARA) {
|
||||
if (getRoom().flags.water)
|
||||
animation.setAnim(ANIM_UNDERWATER);
|
||||
else
|
||||
animation.setAnim(ANIM_STAND);
|
||||
}
|
||||
|
||||
jointChest = 7;
|
||||
jointHead = 14;
|
||||
rangeChest = vec4(-0.40f, 0.40f, -0.90f, 0.90f) * PI;
|
||||
@ -465,6 +457,9 @@ struct Lara : Character {
|
||||
//reset(18, vec3(34914, 11008, 41315), 90 * DEG2RAD); // level 4 (main hall)
|
||||
//reset(19, vec3(33368, 19968, 45643), 270 * DEG2RAD); // level 4 (damocles)
|
||||
//reset(24, vec3(45609, 18176, 41500), 90 * DEG2RAD); // level 4 (thor)
|
||||
//reset(21, vec3(24106, -4352, 52089), 0); // level 6 (flame traps)
|
||||
//reset(73, vec3(73372, -122, 51687), PI * 0.5f); // level 6 (midas hand)
|
||||
//reset(64, vec3(36839, -2560, 48769), 270 * DEG2RAD); // level 6 (flipmap effect)
|
||||
//reset(99, vec3(45562, -3328, 63366), 225 * DEG2RAD); // level 7a (flipmap)
|
||||
//reset(90, vec3(19438, 3840, 78341), 90 * DEG2RAD); // level 7a (statues)
|
||||
//reset(57, vec3(54844, -3328, 53145), 0); // level 8b (bridge switch)
|
||||
@ -473,12 +468,20 @@ struct Lara : Character {
|
||||
//reset(30, vec3(69689, -8448, 34922), 330 * DEG2RAD); // Level 10a (cabin)
|
||||
//reset(27, vec3(52631, -4352, 57893), 270 * DEG2RAD); // Level 10a (drill)
|
||||
//reset(44, vec3(75803, -11008, 21097), 90 * DEG2RAD); // Level 10a (boat)
|
||||
//reset(50, vec3(53703, -18688, 13769), PI); // Level 10c (scion holder)
|
||||
//reset(19, vec3(35364, -512, 40199), PI * 0.5f); // Level 10c (lava flow)
|
||||
//reset(50, vec3(53703, -18688, 13769), PI); // Level 10c (scion holder)
|
||||
//reset(19, vec3(35364, -512, 40199), PI * 0.5f); // Level 10c (lava flow)
|
||||
//reset(9, vec3(69074, -14592, 25192), 0); // Level 10c (trap slam)
|
||||
//reset(10, vec3(90443, 11264 - 256, 114614), PI, STAND_ONWATER); // villa mortal 2
|
||||
#endif
|
||||
chestOffset = animation.getJoints(getMatrix(), 7).pos;
|
||||
|
||||
if (getEntity().type == TR::Entity::LARA) {
|
||||
if (getRoom().flags.water)
|
||||
animation.setAnim(ANIM_UNDERWATER);
|
||||
else
|
||||
animation.setAnim(ANIM_STAND);
|
||||
}
|
||||
|
||||
chestOffset = animation.getJoints(getMatrix(), jointChest).pos;
|
||||
}
|
||||
|
||||
virtual ~Lara() {
|
||||
@ -983,8 +986,8 @@ struct Lara : Character {
|
||||
// head & chest
|
||||
overrideMask |= BODY_CHEST | BODY_HEAD;
|
||||
|
||||
animation.overrides[ 7] = animation.getJointRot( 7);
|
||||
animation.overrides[14] = animation.getJointRot(14);
|
||||
animation.overrides[jointChest] = animation.getJointRot(jointChest);
|
||||
animation.overrides[jointHead] = animation.getJointRot(jointHead);
|
||||
|
||||
/* TODO: shotgun full body animation
|
||||
if (wpnCurrent == Weapon::SHOTGUN) {
|
||||
@ -1396,6 +1399,20 @@ struct Lara : Character {
|
||||
}
|
||||
default : ;
|
||||
}
|
||||
|
||||
if (hitType != TR::HIT_LAVA) {
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(e.room, e.x, e.y, e.z, info);
|
||||
|
||||
if (info.lava && info.floor == e.y)
|
||||
hitType = TR::HIT_LAVA;
|
||||
}
|
||||
|
||||
if (hitType == TR::HIT_LAVA) {
|
||||
for (int i = 0; i < 10; i++)
|
||||
Flame::add(game, this, int(randf() * 24.0f));
|
||||
}
|
||||
};
|
||||
|
||||
bool useItem(TR::Entity::Type item) {
|
||||
@ -1578,6 +1595,11 @@ struct Lara : Character {
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(e.room, e.x, e.y, e.z, info);
|
||||
|
||||
if (info.lava && info.floor == e.y) {
|
||||
hit(LARA_MAX_HEALTH + 1, NULL, TR::HIT_LAVA);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info.trigCmdCount) return; // has no trigger
|
||||
|
||||
TR::Limits::Limit *limit = NULL;
|
||||
@ -2218,10 +2240,10 @@ struct Lara : Character {
|
||||
|
||||
if (state == STATE_SURF_TREAD) {
|
||||
if (animation.isFrameActive(0))
|
||||
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.03f);
|
||||
game->waterDrop(animation.getJoints(getMatrix(), jointHead).pos, 96.0f, 0.03f);
|
||||
} else {
|
||||
if (animation.frameIndex % 4 == 0)
|
||||
game->waterDrop(animation.getJoints(getMatrix(), 14).pos, 96.0f, 0.02f);
|
||||
game->waterDrop(animation.getJoints(getMatrix(), jointHead).pos, 96.0f, 0.02f);
|
||||
}
|
||||
|
||||
if (input & FORTH) {
|
||||
@ -2779,7 +2801,7 @@ struct Lara : Character {
|
||||
|
||||
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
|
||||
Controller::render(frustum, mesh, type, caustics);
|
||||
chestOffset = animation.getJoints(getMatrix(), 7).pos; // TODO: move to update func
|
||||
chestOffset = animation.getJoints(getMatrix(), jointChest).pos; // TODO: move to update func
|
||||
|
||||
if (braid)
|
||||
braid->render(mesh);
|
||||
|
@ -283,7 +283,7 @@ struct Level : IGame {
|
||||
switch (b.flags.mode) {
|
||||
case 0 : flags |= Sound::UNIQUE; break;
|
||||
case 1 : flags |= Sound::REPLAY; break;
|
||||
case 2 : flags |= Sound::STATIC | Sound::LOOP; break;
|
||||
case 2 : flags |= Sound::FLIPPED | Sound::UNFLIPPED | Sound::LOOP; break;
|
||||
}
|
||||
}
|
||||
if (b.flags.gain) volume = max(0.0f, volume - randf() * 0.25f);
|
||||
@ -447,8 +447,8 @@ struct Level : IGame {
|
||||
case TR::Entity::TRAP_BOULDER :
|
||||
entity.controller = new TrapBoulder(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_DARTGUN :
|
||||
entity.controller = new TrapDartgun(this, i);
|
||||
case TR::Entity::TRAP_DART_EMITTER :
|
||||
entity.controller = new TrapDartEmitter(this, i);
|
||||
break;
|
||||
case TR::Entity::DRAWBRIDGE :
|
||||
entity.controller = new Drawbridge(this, i);
|
||||
@ -498,6 +498,9 @@ struct Level : IGame {
|
||||
case TR::Entity::CABIN :
|
||||
entity.controller = new Cabin(this, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_FLAME_EMITTER :
|
||||
entity.controller = new TrapFlameEmitter(this, i);
|
||||
break;
|
||||
case TR::Entity::BOAT :
|
||||
entity.controller = new Boat(this, i);
|
||||
break;
|
||||
|
25
src/sound.h
25
src/sound.h
@ -412,10 +412,9 @@ namespace Sound {
|
||||
PAN = 2,
|
||||
UNIQUE = 4,
|
||||
REPLAY = 8,
|
||||
STATIC = 16,
|
||||
MUSIC = 32,
|
||||
FLIPPED = 64,
|
||||
UNFLIPPED = 128,
|
||||
MUSIC = 16,
|
||||
FLIPPED = 32,
|
||||
UNFLIPPED = 64,
|
||||
};
|
||||
|
||||
bool flipped;
|
||||
@ -607,7 +606,7 @@ namespace Sound {
|
||||
if (music != ((channels[i]->flags & MUSIC) != 0))
|
||||
continue;
|
||||
|
||||
if (channels[i]->flags & STATIC) {
|
||||
if (channels[i]->flags & (FLIPPED | UNFLIPPED)) {
|
||||
if (!(channels[i]->flags & (flipped ? FLIPPED : UNFLIPPED)))
|
||||
continue;
|
||||
|
||||
@ -704,7 +703,7 @@ namespace Sound {
|
||||
Sample* play(Stream *stream, const vec3 &pos, float volume = 1.0f, float pitch = 0.0f, int flags = 0, int id = - 1) {
|
||||
if (!stream) return NULL;
|
||||
if (volume > 0.001f) {
|
||||
if (!(flags & (STATIC | MUSIC)) && (flags & PAN)) {
|
||||
if (!(flags & (FLIPPED | UNFLIPPED | MUSIC)) && (flags & PAN)) {
|
||||
vec3 d = pos - listener.matrix.getPos();
|
||||
if (fabsf(d.x) > SND_FADEOFF_DIST || fabsf(d.y) > SND_FADEOFF_DIST || fabsf(d.z) > SND_FADEOFF_DIST) {
|
||||
delete stream;
|
||||
@ -712,17 +711,23 @@ namespace Sound {
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & (UNIQUE | REPLAY))
|
||||
if (flags & (UNIQUE | REPLAY)) {
|
||||
for (int i = 0; i < channelsCount; i++)
|
||||
if (channels[i]->id == id) {
|
||||
if (!(flags & UNIQUE)) {
|
||||
channels[i]->pos = pos;
|
||||
vec3 p = listener.matrix.getPos();
|
||||
|
||||
if ((p - channels[i]->pos).length2() > (p - pos).length2()) {
|
||||
channels[i]->pos = pos;
|
||||
channels[i]->pitch = pitch;
|
||||
channels[i]->replay();
|
||||
}
|
||||
|
||||
if (flags & REPLAY)
|
||||
channels[i]->replay();
|
||||
|
||||
delete stream;
|
||||
return channels[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (channelsCount < SND_CHANNELS_MAX)
|
||||
return channels[channelsCount++] = new Sample(stream, pos, volume, pitch, flags, id);
|
||||
|
103
src/trigger.h
103
src/trigger.h
@ -56,6 +56,8 @@ struct Gear : Controller {
|
||||
}
|
||||
};
|
||||
|
||||
#define DART_DAMAGE 50
|
||||
|
||||
struct Dart : Controller {
|
||||
vec3 velocity;
|
||||
vec3 dir;
|
||||
@ -74,7 +76,7 @@ struct Dart : Controller {
|
||||
Controller *lara = (Controller*)level->laraController;
|
||||
if (armed && collide(lara)) {
|
||||
Sprite::add(game, TR::Entity::BLOOD, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z, Sprite::FRAME_ANIMATED);
|
||||
lara->hit(50.0f, this);
|
||||
lara->hit(DART_DAMAGE, this);
|
||||
armed = false;
|
||||
}
|
||||
|
||||
@ -95,13 +97,13 @@ struct Dart : Controller {
|
||||
}
|
||||
};
|
||||
|
||||
struct TrapDartgun : Controller {
|
||||
struct TrapDartEmitter : Controller {
|
||||
enum {
|
||||
STATE_IDLE,
|
||||
STATE_FIRE
|
||||
};
|
||||
|
||||
TrapDartgun(IGame *game, int entity) : Controller(game, entity) {}
|
||||
TrapDartEmitter(IGame *game, int entity) : Controller(game, entity) {}
|
||||
|
||||
virtual bool activate() {
|
||||
if (!Controller::activate())
|
||||
@ -114,11 +116,11 @@ struct TrapDartgun : Controller {
|
||||
|
||||
vec3 p = pos + vec3(0.0f, -512.0f, 256.0f).rotateY(PI - entity.rotation);
|
||||
|
||||
int dartIndex = level->entityAdd(TR::Entity::TRAP_DART, entity.room, (int)p.x, (int)p.y, (int)p.z, entity.rotation, entity.intensity);
|
||||
if (dartIndex > -1) {
|
||||
Dart *dart = new Dart(game, dartIndex);
|
||||
int index = level->entityAdd(TR::Entity::TRAP_DART, getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), entity.rotation, entity.intensity);
|
||||
if (index > -1) {
|
||||
Dart *dart = new Dart(game, index);
|
||||
dart->activate();
|
||||
level->entities[dartIndex].controller = dart;
|
||||
level->entities[index].controller = dart;
|
||||
}
|
||||
|
||||
Sprite::add(game, TR::Entity::SMOKE, entity.room, (int)p.x, (int)p.y, (int)p.z);
|
||||
@ -137,6 +139,91 @@ struct TrapDartgun : Controller {
|
||||
}
|
||||
};
|
||||
|
||||
#define FLAME_HEAT_DAMAGE 90
|
||||
#define FLAME_BURN_DAMAGE 150
|
||||
|
||||
struct Flame : Sprite {
|
||||
|
||||
static Flame* add(IGame *game, Controller *controller, int jointIndex) {
|
||||
Flame *flame = NULL;
|
||||
|
||||
TR::Level *level = game->getLevel();
|
||||
int roomIndex = controller->getRoomIndex();
|
||||
vec3 pos = controller->pos;
|
||||
|
||||
int index = level->entityAdd(TR::Entity::TRAP_FLAME, roomIndex, int(pos.x), int(pos.y), int(pos.z), 0, 0);
|
||||
if (index > -1) {
|
||||
flame = new Flame(game, index, jointIndex);
|
||||
level->entities[index].controller = flame;
|
||||
}
|
||||
return flame;
|
||||
}
|
||||
|
||||
int jointIndex;
|
||||
float sleep;
|
||||
|
||||
Flame(IGame *game, int entity, int jointIndex) : Sprite(game, entity, false, Sprite::FRAME_ANIMATED), jointIndex(jointIndex), sleep(0.0f) {
|
||||
time = randf() * 3.0f;
|
||||
activate();
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
Sprite::update();
|
||||
game->playSound(TR::SND_FLAME, pos, Sound::PAN);
|
||||
|
||||
Character *lara = (Character*)level->laraController;
|
||||
|
||||
if (jointIndex > -1) {
|
||||
if (lara->stand == Character::STAND_UNDERWATER) {
|
||||
level->entityRemove(entity);
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
pos = lara->animation.getJoints(lara->getMatrix(), jointIndex).pos;
|
||||
if (jointIndex == 0)
|
||||
pos.y += 100.0f;
|
||||
|
||||
lara->hit(FLAME_BURN_DAMAGE * Core::deltaTime, this);
|
||||
} else
|
||||
if (lara->health > 0.0f) {
|
||||
if (sleep > 0.0f)
|
||||
sleep = max(0.0f, sleep - Core::deltaTime);
|
||||
|
||||
if (sleep == 0.0f && lara->collide(Sphere(pos, 600.0f))) {
|
||||
lara->hit(FLAME_HEAT_DAMAGE * Core::deltaTime, this);
|
||||
|
||||
if (lara->collide(Sphere(pos, 300.0f))) {
|
||||
Flame::add(game, lara, 0);
|
||||
sleep = 3.0f; // stay inactive for 3 seconds
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct TrapFlameEmitter : Controller {
|
||||
Flame *flame;
|
||||
|
||||
TrapFlameEmitter(IGame *game, int entity) : Controller(game, entity), flame(NULL) {}
|
||||
|
||||
void virtual update() {
|
||||
if (!isActive()) {
|
||||
if (flame) {
|
||||
level->entityRemove(flame->entity);
|
||||
delete flame;
|
||||
flame = NULL;
|
||||
Sound::stop(TR::SND_FLAME);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (flame) return;
|
||||
|
||||
flame = Flame::add(game, this, -1);
|
||||
}
|
||||
};
|
||||
|
||||
#define BOULDER_DAMAGE_GROUND 1000
|
||||
#define BOULDER_DAMAGE_AIR 100
|
||||
|
||||
@ -694,7 +781,7 @@ struct TrapLava : Controller {
|
||||
virtual void update() {
|
||||
Character *lara = (Character*)level->laraController;
|
||||
if (lara->health > 0.0f && collide(lara))
|
||||
lara->hit(1000.0f, this, TR::HIT_FLAME);
|
||||
lara->hit(1001.0f, this, TR::HIT_LAVA);
|
||||
|
||||
if (done) {
|
||||
deactivate();
|
||||
|
80
src/utils.h
80
src/utils.h
@ -773,6 +773,41 @@ vec3 boxNormal(int x, int z) {
|
||||
return x < z ? vec3(-1, 0, 0) : vec3(0, 0, -1);
|
||||
}
|
||||
|
||||
|
||||
struct Sphere {
|
||||
vec3 center;
|
||||
float radius;
|
||||
|
||||
Sphere() {}
|
||||
Sphere(const vec3 ¢er, float radius) : center(center), radius(radius) {}
|
||||
|
||||
bool intersect(const Sphere &s) const {
|
||||
float d = (center - s.center).length2();
|
||||
float r = (radius + s.radius);
|
||||
return d < r * r;
|
||||
}
|
||||
|
||||
bool intersect(const vec3 &rayPos, const vec3 &rayDir, float &t) const {
|
||||
vec3 v = rayPos - center;
|
||||
float h = -v.dot(rayDir);
|
||||
float d = h * h + radius * radius - v.length2();
|
||||
|
||||
if (d > 0.0f) {
|
||||
d = sqrtf(d);
|
||||
float tMin = h - d;
|
||||
float tMax = h + d;
|
||||
if (tMax > 0.0f) {
|
||||
if (tMin < 0.0f)
|
||||
tMin = 0.0f;
|
||||
t = tMin;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Box {
|
||||
vec3 min, max;
|
||||
|
||||
@ -872,6 +907,12 @@ struct Box {
|
||||
max += offset;
|
||||
}
|
||||
|
||||
vec3 closestPoint(const vec3 &p) const {
|
||||
return vec3(clamp(p.x, min.x, max.x),
|
||||
clamp(p.y, min.y, max.y),
|
||||
clamp(p.z, min.z, max.z));
|
||||
}
|
||||
|
||||
bool contains(const vec3 &v) const {
|
||||
return v.x >= min.x && v.x <= max.x && v.y >= min.y && v.y <= max.y && v.z >= min.z && v.z <= max.z;
|
||||
}
|
||||
@ -918,6 +959,13 @@ struct Box {
|
||||
return !((max.x < box.min.x || min.x > box.max.x) || (max.y < box.min.y || min.y > box.max.y) || (max.z < box.min.z || min.z > box.max.z));
|
||||
}
|
||||
|
||||
bool intersect(const Sphere &sphere) const {
|
||||
if (contains(sphere.center))
|
||||
return true;
|
||||
vec3 dir = sphere.center - closestPoint(sphere.center);
|
||||
return (dir.length2() < sphere.radius * sphere.radius);
|
||||
}
|
||||
|
||||
bool intersect(const vec3 &rayPos, const vec3 &rayDir, float &t) const {
|
||||
float tMax = INF, tMin = -tMax;
|
||||
|
||||
@ -940,38 +988,6 @@ struct Box {
|
||||
}
|
||||
};
|
||||
|
||||
struct Sphere {
|
||||
vec3 center;
|
||||
float radius;
|
||||
|
||||
Sphere() {}
|
||||
Sphere(const vec3 ¢er, float radius) : center(center), radius(radius) {}
|
||||
|
||||
bool intersect(const Sphere &s) const {
|
||||
float d = (center - s.center).length2();
|
||||
float r = (radius + s.radius);
|
||||
return d < r * r;
|
||||
}
|
||||
|
||||
bool intersect(const vec3 &rayPos, const vec3 &rayDir, float &t) const {
|
||||
vec3 v = rayPos - center;
|
||||
float h = -v.dot(rayDir);
|
||||
float d = h * h + radius * radius - v.length2();
|
||||
|
||||
if (d > 0.0f) {
|
||||
d = sqrtf(d);
|
||||
float tMin = h - d;
|
||||
float tMax = h + d;
|
||||
if (tMax > 0.0f) {
|
||||
if (tMin < 0.0f)
|
||||
tMin = 0.0f;
|
||||
t = tMin;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Stream {
|
||||
static char cacheDir[255];
|
||||
|
Loading…
x
Reference in New Issue
Block a user