mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-06 13:16:52 +02:00
#9 fading & panning of sound sources
This commit is contained in:
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
48
src/camera.h
48
src/camera.h
@@ -160,6 +160,7 @@ struct Camera : Controller {
|
||||
|
||||
float fov, znear, zfar;
|
||||
vec3 target, destPos, lastDest, angleAdv;
|
||||
mat4 mViewInv;
|
||||
int room;
|
||||
|
||||
float timer;
|
||||
@@ -266,29 +267,32 @@ struct Camera : Controller {
|
||||
|
||||
pos = pos.lerp(destPos, Core::deltaTime * lerpFactor);
|
||||
|
||||
if (actCamera > -1) return;
|
||||
if (actCamera <= -1) {
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(room, (int)pos.x, (int)pos.z, info);
|
||||
|
||||
if (info.roomNext != 255)
|
||||
room = info.roomNext;
|
||||
|
||||
if (pos.y < info.ceiling) {
|
||||
if (info.roomAbove != 255)
|
||||
room = info.roomAbove;
|
||||
else
|
||||
if (info.ceiling != 0xffff8100)
|
||||
pos.y = info.ceiling;
|
||||
}
|
||||
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(room, (int)pos.x, (int)pos.z, info);
|
||||
|
||||
if (info.roomNext != 255)
|
||||
room = info.roomNext;
|
||||
|
||||
if (pos.y < info.ceiling) {
|
||||
if (info.roomAbove != 255)
|
||||
room = info.roomAbove;
|
||||
else
|
||||
if (info.ceiling != 0xffff8100)
|
||||
pos.y = info.ceiling;
|
||||
if (pos.y > info.floor) {
|
||||
if (info.roomBelow != 255)
|
||||
room = info.roomBelow;
|
||||
else
|
||||
if (info.floor != 0xffff8100)
|
||||
pos.y = info.floor;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos.y > info.floor) {
|
||||
if (info.roomBelow != 255)
|
||||
room = info.roomBelow;
|
||||
else
|
||||
if (info.floor != 0xffff8100)
|
||||
pos.y = info.floor;
|
||||
}
|
||||
mViewInv = mat4(pos, target, vec3(0, -1, 0));
|
||||
Sound::listener.matrix = mViewInv;
|
||||
}
|
||||
|
||||
vec3 trace(int fromRoom, const vec3 &from, const vec3 &to) { // TODO: use Bresenham
|
||||
@@ -352,7 +356,7 @@ struct Camera : Controller {
|
||||
}
|
||||
|
||||
virtual void setup() {
|
||||
Core::mViewInv = mat4(pos, target, vec3(0, -1, 0));
|
||||
Core::mViewInv = mViewInv;
|
||||
Core::mView = Core::mViewInv.inverse();
|
||||
Core::mProj = mat4(fov, (float)Core::width / (float)Core::height, znear, zfar);
|
||||
|
||||
@@ -360,7 +364,7 @@ struct Camera : Controller {
|
||||
Core::viewPos = Core::mViewInv.offset.xyz;
|
||||
|
||||
frustum->pos = Core::viewPos;
|
||||
frustum->calcPlanes(Core::mViewProj);
|
||||
frustum->calcPlanes(Core::mViewProj);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -166,7 +166,7 @@ struct Controller {
|
||||
return b.floor - floor;
|
||||
}
|
||||
|
||||
void playSound(int id) const {
|
||||
void playSound(int id, const vec3 &pos, int flags) const {
|
||||
// LOG("play sound %d\n", id);
|
||||
|
||||
int16 a = level->soundsMap[id];
|
||||
@@ -175,7 +175,7 @@ struct Controller {
|
||||
if (b.chance == 0 || (rand() & 0x7fff) <= b.chance) {
|
||||
uint32 c = level->soundOffsets[b.offset + rand() % ((b.flags & 0xFF) >> 2)];
|
||||
void *p = &level->soundData[c];
|
||||
Sound::play(new Stream(p, 1024 * 1024), (float)b.volume / 0xFFFF, 0.0f, Sound::Flags::PAN);
|
||||
Sound::play(new Stream(p, 1024 * 1024), pos, (float)b.volume / 0xFFFF, 0.0f, flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +198,27 @@ struct Controller {
|
||||
angle.y = k * PI * 0.5f; // clamp angle to n*PI/2
|
||||
}
|
||||
|
||||
virtual Box getBoundingBox() {
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
TR::Model &model = getModel();
|
||||
|
||||
float k = animTime * 30.0f / anim->frameRate;
|
||||
int fIndex = (int)k;
|
||||
int fCount = (anim->frameEnd - anim->frameStart) / anim->frameRate + 1;
|
||||
|
||||
int fSize = sizeof(TR::AnimFrame) + model.mCount * sizeof(uint16) * 2;
|
||||
k = k - fIndex;
|
||||
|
||||
int fIndexA = fIndex % fCount, fIndexB = (fIndex + 1) % fCount;
|
||||
TR::AnimFrame *fA = (TR::AnimFrame*)&level->frameData[(anim->frameOffset + fIndexA * fSize) >> 1];
|
||||
TR::AnimFrame *fB = (TR::AnimFrame*)&level->frameData[(anim->frameOffset + fIndexB * fSize) >> 1];
|
||||
Box box(fA->box.min().lerp(fB->box.min(), k), fA->box.max().lerp(fB->box.max(), k));
|
||||
box.rotate90(getEntity().rotation.value / 0x4000);
|
||||
box.min += pos;
|
||||
box.max += pos;
|
||||
return box;
|
||||
}
|
||||
|
||||
void collide() {
|
||||
TR::Entity &entity = getEntity();
|
||||
|
||||
@@ -255,7 +276,7 @@ struct Controller {
|
||||
case TR::Action::SECRET :
|
||||
if (!level->secrets[next->value]) {
|
||||
level->secrets[next->value] = true;
|
||||
playSound(TR::SND_SECRET);
|
||||
playSound(TR::SND_SECRET, pos, 0);
|
||||
}
|
||||
actionCommand = next;
|
||||
activateNext();
|
||||
@@ -411,12 +432,12 @@ struct Controller {
|
||||
if (cmd == TR::ANIM_CMD_EFFECT) {
|
||||
switch (id) {
|
||||
case TR::EFFECT_ROTATE_180 : angle.y = angle.y + PI; break;
|
||||
case TR::EFFECT_LARA_BUBBLES : if (rand() % 10 > 6) playSound(TR::SND_BUBBLE); break;
|
||||
case TR::EFFECT_LARA_BUBBLES : if (rand() % 10 > 6) playSound(TR::SND_BUBBLE, pos, Sound::Flags::PAN); break;
|
||||
case TR::EFFECT_LARA_HANDSFREE : break;
|
||||
default : LOG("unknown special cmd %d (anim %d)\n", id, animIndex);
|
||||
}
|
||||
} else
|
||||
playSound(id);
|
||||
playSound(id, pos, Sound::Flags::PAN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
13
src/debug.h
13
src/debug.h
@@ -295,7 +295,7 @@ namespace Debug {
|
||||
void debugSectors(const TR::Level &level, const vec3 &pos, int roomIndex) {
|
||||
TR::Room &room = level.rooms[roomIndex];
|
||||
|
||||
vec3 p = (pos - vec3(room.info.x, 0, room.info.z)) / vec3(1024, 1, 1024);
|
||||
vec3 p = (pos - vec3(room.info.x, 0, room.info.z)) * vec3(1.0f / 1024.0f, 1, 1.0f / 1024.0f);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
for (int z = 0; z < room.zSectors; z++)
|
||||
@@ -409,14 +409,15 @@ namespace Debug {
|
||||
TR::StaticMesh *sm = level.getMeshByID(m.meshID);
|
||||
ASSERT(sm != NULL);
|
||||
|
||||
vec3 min, max, offset = vec3(m.x, m.y, m.z);
|
||||
sm->getBox(false, m.rotation, min, max); // visible box
|
||||
Box box;
|
||||
vec3 offset = vec3(m.x, m.y, m.z);
|
||||
sm->getBox(false, m.rotation, box); // visible box
|
||||
|
||||
Debug::Draw::box(offset + min, offset + max, vec4(1, 1, 0, 0.25));
|
||||
Debug::Draw::box(offset + box.min, offset + box.max, vec4(1, 1, 0, 0.25));
|
||||
|
||||
if (sm->flags == 2) { // collision box
|
||||
sm->getBox(true, m.rotation, min, max);
|
||||
Debug::Draw::box(offset + min - vec3(10.0f), offset + max + vec3(10.0f), vec4(1, 0, 0, 0.50));
|
||||
sm->getBox(true, m.rotation, box);
|
||||
Debug::Draw::box(offset + box.min - vec3(10.0f), offset + box.max + vec3(10.0f), vec4(1, 0, 0, 0.50));
|
||||
}
|
||||
/*
|
||||
TR::Mesh *mesh = (TR::Mesh*)&level.meshData[level.meshOffsets[sm->mesh] / 2];
|
||||
|
28
src/format.h
28
src/format.h
@@ -75,6 +75,7 @@ namespace TR {
|
||||
SND_NO = 2,
|
||||
SND_LANDING = 4,
|
||||
SND_BUBBLE = 37,
|
||||
SND_DART = 151,
|
||||
SND_SECRET = 173,
|
||||
};
|
||||
|
||||
@@ -472,34 +473,17 @@ namespace TR {
|
||||
MinMax cbox;
|
||||
uint16 flags;
|
||||
|
||||
void getBox(bool collision, angle rotation, vec3 &min, vec3 &max) {
|
||||
void getBox(bool collision, angle rotation, ::Box &box) {
|
||||
int k = rotation.value / 0x4000;
|
||||
|
||||
MinMax &m = collision ? cbox : vbox;
|
||||
|
||||
ASSERT(m.minX <= m.maxX && m.minY <= m.maxY && m.minZ <= m.maxZ);
|
||||
|
||||
switch (k) {
|
||||
case 0 :
|
||||
min = vec3(m.minX, m.minY, m.minZ);
|
||||
max = vec3(m.maxX, m.maxY, m.maxZ);
|
||||
break;
|
||||
case 1 :
|
||||
min = vec3(m.minZ, m.minY, -m.maxX);
|
||||
max = vec3(m.maxZ, m.maxY, -m.minX);
|
||||
break;
|
||||
case 2 :
|
||||
min = vec3(-m.maxX, m.minY, -m.maxZ);
|
||||
max = vec3(-m.minX, m.maxY, -m.minZ);
|
||||
break;
|
||||
case 3 :
|
||||
min = vec3(-m.maxZ, m.minY, m.minX);
|
||||
max = vec3(-m.minZ, m.maxY, m.maxX);
|
||||
break;
|
||||
default :
|
||||
ASSERT(false);
|
||||
}
|
||||
ASSERT(min.x <= max.x && min.y <= max.y && min.z <= max.z);
|
||||
box = ::Box(m.min(), m.max());
|
||||
box.rotate90(k);
|
||||
|
||||
ASSERT(box.min.x <= box.max.x && box.min.y <= box.max.y && box.min.z <= box.max.z);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -17,7 +17,7 @@ namespace Game {
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
//Sound::play(Sound::openWAD("05_Lara's_Themes.wav"), 1, 1, 0);
|
||||
Sound::play(new Stream("05.ogg"), 1, 1, 0);
|
||||
Sound::play(new Stream("05.ogg"), vec3(0.0f), 1, 1, Sound::Flags::LOOP);
|
||||
//Sound::play(new Stream("03.mp3"), 1, 1, 0);
|
||||
#endif
|
||||
}
|
||||
|
47
src/lara.h
47
src/lara.h
@@ -144,11 +144,16 @@ struct Lara : Controller {
|
||||
angle = vec3(0.0f, PI * 0.5f, 0.0f);
|
||||
getEntity().room = 12;
|
||||
*/
|
||||
|
||||
/*
|
||||
// level 2 (pool)
|
||||
pos = vec3(70067, -256, 29104);
|
||||
angle = vec3(0.0f, -0.68f, 0.0f);
|
||||
getEntity().room = 15;
|
||||
*/
|
||||
// level 2 (blade)
|
||||
pos = vec3(27221, -1024, 29205);
|
||||
angle = vec3(0.0f, PI * 0.5f, 0.0f);
|
||||
getEntity().room = 61;
|
||||
|
||||
/*
|
||||
// level 2 (wolf)
|
||||
@@ -323,7 +328,7 @@ struct Lara : Controller {
|
||||
for (int i = 0; i < info.trigCmdCount; i++) {
|
||||
if (!controller) {
|
||||
LOG("! next activation entity %d has no controller\n", level->entities[info.trigCmd[i].args].type);
|
||||
playSound(TR::SND_NO);
|
||||
playSound(TR::SND_NO, pos, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -420,7 +425,7 @@ struct Lara : Controller {
|
||||
if (stand == STAND_SLIDE || (stand == STAND_AIR && velocity.y > 0) || stand == STAND_GROUND) {
|
||||
if (e.y + 8 >= info.floor && (abs(info.slantX) > 2 || abs(info.slantZ) > 2)) {
|
||||
if (stand == STAND_AIR)
|
||||
playSound(TR::SND_LANDING);
|
||||
playSound(TR::SND_LANDING, pos, Sound::Flags::PAN);
|
||||
pos.y = info.floor;
|
||||
updateEntity();
|
||||
|
||||
@@ -928,8 +933,9 @@ struct Lara : Controller {
|
||||
vec3 p = pos;
|
||||
pos = pos + offset;
|
||||
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(getEntity().room, (int)pos.x, (int)pos.z, info, true);
|
||||
level->getFloorInfo(e.room, (int)pos.x, (int)pos.z, info, true);
|
||||
|
||||
// get frame to get height
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
@@ -937,7 +943,40 @@ struct Lara : Controller {
|
||||
bool canPassGap = (info.floor - info.ceiling) >= (stand == STAND_GROUND ? 768 : 512);
|
||||
float f = info.floor - pos.y;
|
||||
float c = pos.y - info.ceiling;
|
||||
/*
|
||||
Box eBox = Box(pos - vec3(128.0f, 0.0f, 128.0f), pos + vec3(128.0, getHeight(), 128.0f)); // getBoundingBox();
|
||||
// check static meshes in the room
|
||||
if (canPassGap) {
|
||||
TR::Room &r = level->rooms[e.room];
|
||||
for (int i = 0; i < r.meshesCount; i++) {
|
||||
TR::Room::Mesh &m = r.meshes[i];
|
||||
TR::StaticMesh *sm = level->getMeshByID(m.meshID);
|
||||
if (sm->flags != 2) continue; // no have collision box
|
||||
|
||||
Box mBox;
|
||||
vec3 offset(m.x, m.y, m.z);
|
||||
sm->getBox(true, m.rotation, mBox);
|
||||
mBox.min += offset;
|
||||
mBox.max += offset;
|
||||
|
||||
if (eBox.intersect(mBox)) {
|
||||
canPassGap = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check entities in the room
|
||||
if (canPassGap)
|
||||
for (int i = 0; i < level->entitiesCount; i++)
|
||||
if (i != entity && level->entities[i].room == e.room && level->entities[i].controller) {
|
||||
Box mBox = ((Controller*)level->entities[i].controller)->getBoundingBox();
|
||||
if (eBox.intersect(mBox)) {
|
||||
canPassGap = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (canPassGap)
|
||||
switch (stand) {
|
||||
case STAND_AIR : {
|
||||
|
11
src/level.h
11
src/level.h
@@ -238,10 +238,11 @@ struct Level {
|
||||
ASSERT(sMesh != NULL);
|
||||
|
||||
// check visibility
|
||||
vec3 min, max, offset = vec3(rMesh.x, rMesh.y, rMesh.z);
|
||||
sMesh->getBox(false, rMesh.rotation, min, max);
|
||||
if (!camera->frustum->isVisible(offset + min, offset + max))
|
||||
continue;
|
||||
Box box;
|
||||
vec3 offset = vec3(rMesh.x, rMesh.y, rMesh.z);
|
||||
sMesh->getBox(false, rMesh.rotation, box);
|
||||
if (!camera->frustum->isVisible(offset + box.min, offset + box.max))
|
||||
continue;
|
||||
rMesh.flags.rendered = true;
|
||||
|
||||
// set light parameters
|
||||
@@ -362,7 +363,7 @@ struct Level {
|
||||
m.translate(pos);
|
||||
m.rotateY(angle);
|
||||
m.translate(vec3(offset.x, 0.0f, offset.z));
|
||||
m.scale(vec3(size.x, 0.0f, size.z) / 1024.0f);
|
||||
m.scale(vec3(size.x, 0.0f, size.z) * (1.0f / 1024.0f));
|
||||
|
||||
Core::active.shader->setParam(uModel, m);
|
||||
Core::active.shader->setParam(uColor, vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
|
48
src/sound.h
48
src/sound.h
@@ -20,6 +20,7 @@
|
||||
#endif
|
||||
|
||||
#define SND_CHANNELS_MAX 32
|
||||
#define SND_FADEOFF_DIST (1024.0f * 5.0f)
|
||||
|
||||
namespace Sound {
|
||||
|
||||
@@ -216,7 +217,7 @@ namespace Sound {
|
||||
|
||||
struct Listener {
|
||||
mat4 matrix;
|
||||
vec3 velocity;
|
||||
// vec3 velocity;
|
||||
} listener;
|
||||
|
||||
enum Flags {
|
||||
@@ -229,12 +230,14 @@ namespace Sound {
|
||||
|
||||
struct Sample {
|
||||
Decoder *decoder;
|
||||
vec3 pos;
|
||||
vec3 velocity;
|
||||
float volume;
|
||||
float pitch;
|
||||
int flags;
|
||||
bool isPlaying;
|
||||
|
||||
Sample(Stream *stream, float volume, float pitch, int flags) : decoder(NULL), volume(volume), pitch(pitch), flags(flags) {
|
||||
Sample(Stream *stream, const vec3 &pos, float volume, float pitch, int flags) : decoder(NULL), pos(pos), volume(volume), pitch(pitch), flags(flags) {
|
||||
uint32 fourcc;
|
||||
stream->read(fourcc);
|
||||
if (fourcc == FOURCC("RIFF")) { // wav
|
||||
@@ -286,6 +289,21 @@ namespace Sound {
|
||||
delete decoder;
|
||||
}
|
||||
|
||||
vec3 getPan() {
|
||||
if (!(flags & PAN))
|
||||
return vec3(1.0f);
|
||||
mat4 m = Sound::listener.matrix;
|
||||
vec3 v = pos - m.offset.xyz;
|
||||
|
||||
float dist = max(0.0f, 1.0f - (v.length2() / (SND_FADEOFF_DIST * SND_FADEOFF_DIST)));
|
||||
float pan = m.right.xyz.dot(v.normal());
|
||||
|
||||
float l = min(1.0f, 1.0f - pan);
|
||||
float r = min(1.0f, 1.0f + pan);
|
||||
|
||||
return vec3(l, r, 1.0f) * dist;
|
||||
}
|
||||
|
||||
bool render(Frame *frames, int count) {
|
||||
if (!isPlaying) return 0;
|
||||
int i = 0;
|
||||
@@ -298,14 +316,15 @@ namespace Sound {
|
||||
i += res;
|
||||
}
|
||||
|
||||
if (volume != 1.0f)
|
||||
vec3 pan = getPan() * volume;
|
||||
|
||||
if (pan.x < 1.0f || pan.y < 1.0f)
|
||||
for (int j = 0; j < i; j++) {
|
||||
frames[j].L = int(frames[j].L * volume);
|
||||
frames[j].R = int(frames[j].R * volume);
|
||||
frames[j].L = int(frames[j].L * pan.x);
|
||||
frames[j].R = int(frames[j].R * pan.y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} *channels[SND_CHANNELS_MAX];
|
||||
int channelsCount;
|
||||
|
||||
@@ -338,7 +357,7 @@ namespace Sound {
|
||||
|
||||
memset(buffer, 0, sizeof(Frame) * count);
|
||||
channels[i]->render(buffer, count);
|
||||
|
||||
|
||||
for (int j = 0; j < count; j++) {
|
||||
result[j].L += buffer[j].L;
|
||||
result[j].R += buffer[j].R;
|
||||
@@ -382,14 +401,15 @@ namespace Sound {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void play(Stream *stream, float volume, float pitch, int flags) {
|
||||
if (!stream) return;
|
||||
Sample* play(Stream *stream, const vec3 &pos, float volume, float pitch, int flags) {
|
||||
if (!stream) return NULL;
|
||||
|
||||
if (channelsCount < SND_CHANNELS_MAX)
|
||||
channels[channelsCount++] = new Sample(stream, volume, pitch, flags);
|
||||
else {
|
||||
LOG("! no free channels\n");
|
||||
delete stream;
|
||||
}
|
||||
return channels[channelsCount++] = new Sample(stream, pos, volume, pitch, flags);
|
||||
|
||||
LOG("! no free channels\n");
|
||||
delete stream;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -107,8 +107,8 @@ struct Dartgun : Trigger {
|
||||
level->entities[dartIndex].controller = new Dart(level, dartIndex);
|
||||
|
||||
addSprite(level, TR::Entity::SMOKE, entity.room, (int)pos.x, (int)pos.y, (int)pos.z);
|
||||
|
||||
playSound(151);
|
||||
|
||||
playSound(TR::SND_DART, pos, Sound::Flags::PAN);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
53
src/utils.h
53
src/utils.h
@@ -76,12 +76,12 @@ inline const int sign(const T &x) {
|
||||
}
|
||||
|
||||
float clampAngle(float a) {
|
||||
return a < -PI ? a + PI2 : (a >= PI ? a - PI2 : a);
|
||||
return a < -PI ? a + PI2 : (a >= PI ? a - PI2 : a);
|
||||
}
|
||||
|
||||
float shortAngle(float a, float b) {
|
||||
float n = clampAngle(b) - clampAngle(a);
|
||||
return clampAngle(n - int(n / PI2) * PI2);
|
||||
float n = clampAngle(b) - clampAngle(a);
|
||||
return clampAngle(n - int(n / PI2) * PI2);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,10 +111,14 @@ struct vec3 {
|
||||
|
||||
float& operator [] (int index) const { return ((float*)this)[index]; }
|
||||
|
||||
vec3& operator += (const vec3 &v) { x += v.x; y += v.y; z += v.z; return *this; }
|
||||
vec3& operator -= (const vec3 &v) { x -= v.x; y -= v.y; z -= v.z; return *this; }
|
||||
vec3& operator *= (const vec3 &v) { x *= v.x; y *= v.y; z *= v.z; return *this; }
|
||||
vec3& operator *= (float s) { x *= s; y *= s; z *= s; return *this; }
|
||||
|
||||
vec3 operator + (const vec3 &v) const { return vec3(x+v.x, y+v.y, z+v.z); }
|
||||
vec3 operator - (const vec3 &v) const { return vec3(x-v.x, y-v.y, z-v.z); }
|
||||
vec3 operator * (const vec3 &v) const { return vec3(x*v.x, y*v.y, z*v.z); }
|
||||
vec3 operator / (const vec3 &v) const { return vec3(x/v.x, y/v.y, z/v.z); }
|
||||
vec3 operator * (float s) const { return vec3(x*s, y*s, z*s); }
|
||||
|
||||
float dot(const vec3 &v) const { return x*v.x + y*v.y + z*v.z; }
|
||||
@@ -484,12 +488,33 @@ struct mat4 {
|
||||
}
|
||||
};
|
||||
|
||||
struct Box {
|
||||
vec3 min, max;
|
||||
|
||||
Box() {}
|
||||
Box(const vec3 &min, const vec3 &max) : min(min), max(max) {}
|
||||
|
||||
void rotate90(int n) {
|
||||
switch (n) {
|
||||
case 0 : break;
|
||||
case 1 : *this = Box(vec3( min.z, min.y, -max.x), vec3( max.z, max.y, -min.x)); break;
|
||||
case 2 : *this = Box(vec3(-max.x, min.y, -max.z), vec3(-min.x, max.y, -min.z)); break;
|
||||
case 3 : *this = Box(vec3(-max.z, min.y, min.x), vec3(-min.z, max.y, max.x)); break;
|
||||
default : ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool intersect(const Box &box) const {
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
struct Stream {
|
||||
FILE *f;
|
||||
const char *data;
|
||||
int size, pos;
|
||||
const char *data;
|
||||
int size, pos;
|
||||
|
||||
Stream(const void *data, int size) : f(NULL), data((char*)data), size(size), pos(0) {}
|
||||
Stream(const void *data, int size) : f(NULL), data((char*)data), size(size), pos(0) {}
|
||||
|
||||
Stream(const char *name) : data(NULL), size(-1), pos(0) {
|
||||
f = fopen(name, "rb");
|
||||
@@ -500,12 +525,12 @@ struct Stream {
|
||||
}
|
||||
|
||||
~Stream() {
|
||||
if (f) fclose(f);
|
||||
if (f) fclose(f);
|
||||
}
|
||||
|
||||
void setPos(int pos) {
|
||||
this->pos = pos;
|
||||
if (f) fseek(f, pos, SEEK_SET);
|
||||
if (f) fseek(f, pos, SEEK_SET);
|
||||
}
|
||||
|
||||
void seek(int offset) {
|
||||
@@ -515,11 +540,11 @@ struct Stream {
|
||||
}
|
||||
|
||||
void raw(void *data, int count) {
|
||||
if (f)
|
||||
fread(data, 1, count, f);
|
||||
else
|
||||
memcpy(data, this->data + pos, count);
|
||||
pos += count;
|
||||
if (f)
|
||||
fread(data, 1, count, f);
|
||||
else
|
||||
memcpy(data, this->data + pos, count);
|
||||
pos += count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
Reference in New Issue
Block a user