mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-28 07:20:26 +02:00
#15 TR3 level format support
This commit is contained in:
@@ -373,7 +373,7 @@ struct Camera : ICamera {
|
||||
|
||||
fov = firstPerson ? 90.0f : 65.0f;
|
||||
znear = firstPerson ? 8.0f : 32.0f;
|
||||
zfar = 40.0f * 1024.0f;
|
||||
zfar = 45.0f * 1024.0f;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -375,6 +375,24 @@ struct Controller {
|
||||
info.climb = (*fd++).data; // climb mask
|
||||
break;
|
||||
|
||||
case 0x07 :
|
||||
case 0x08 :
|
||||
case 0x09 :
|
||||
case 0x0A :
|
||||
case 0x0B :
|
||||
case 0x0C :
|
||||
case 0x0D :
|
||||
case 0x0E :
|
||||
case 0x0F :
|
||||
case 0x10 :
|
||||
case 0x11 :
|
||||
case 0x12 : break; // TODO TR3 triangulation
|
||||
|
||||
case 0x13 : break; // TODO TR3 monkeyswing
|
||||
|
||||
case 0x14 :
|
||||
case 0x15 : break; // TODO TR3 minecart
|
||||
|
||||
default : LOG("unknown func: %d\n", cmd.func);
|
||||
}
|
||||
|
||||
|
@@ -334,8 +334,8 @@ namespace Core {
|
||||
#define MAX_CACHED_LIGHTS 3
|
||||
#define MAX_RENDER_BUFFERS 32
|
||||
#define MAX_CONTACTS 15
|
||||
#define MAX_ANIM_TEX_RANGES 16
|
||||
#define MAX_ANIM_TEX_OFFSETS 32
|
||||
#define MAX_ANIM_TEX_RANGES 32
|
||||
#define MAX_ANIM_TEX_OFFSETS 130
|
||||
|
||||
struct Shader;
|
||||
struct Texture;
|
||||
|
1237
src/format.h
1237
src/format.h
File diff suppressed because it is too large
Load Diff
@@ -155,7 +155,7 @@ struct Inventory {
|
||||
if (!stream) return;
|
||||
Inventory *inv = (Inventory*)userData;
|
||||
|
||||
inv->background[0] = Texture::LoadPCX(*stream);
|
||||
inv->background[0] = Texture::Load(*stream);
|
||||
delete stream;
|
||||
}
|
||||
|
||||
@@ -207,6 +207,8 @@ struct Inventory {
|
||||
new Stream("level/TITLEH.PCX", loadTitleBG, this);
|
||||
if (level->version & TR::VER_TR2)
|
||||
new Stream("level/2/TITLE.PCX", loadTitleBG, this);
|
||||
if (level->version & TR::VER_TR3)
|
||||
new Stream("level/3/TITLEUK.BMP", loadTitleBG, this);
|
||||
|
||||
} else {
|
||||
add(TR::Entity::INV_COMPASS);
|
||||
@@ -445,13 +447,22 @@ struct Inventory {
|
||||
game->playSound(TR::SND_INV_PAGE);
|
||||
item->value = 1;
|
||||
|
||||
passportSlotCount = 2;
|
||||
if (level->version & TR::VER_TR1) {
|
||||
passportSlots[0] = TR::LVL_TR1_1;
|
||||
passportSlots[1] = TR::LVL_TR1_2;
|
||||
} else {
|
||||
passportSlots[0] = TR::LVL_TR2_WALL;
|
||||
passportSlots[1] = TR::LVL_TR2_BOAT;
|
||||
switch (level->version & TR::VER_VERSION) {
|
||||
case TR::VER_TR1 :
|
||||
passportSlotCount = 2;
|
||||
passportSlots[0] = TR::LVL_TR1_1;
|
||||
passportSlots[1] = TR::LVL_TR1_2;
|
||||
break;
|
||||
case TR::VER_TR2 :
|
||||
passportSlotCount = 2;
|
||||
passportSlots[0] = TR::LVL_TR2_WALL;
|
||||
passportSlots[1] = TR::LVL_TR2_BOAT;
|
||||
break;
|
||||
case TR::VER_TR3 :
|
||||
passportSlotCount = 1;
|
||||
passportSlots[0] = TR::LVL_TR3_JUNGLE;
|
||||
break;
|
||||
default : ASSERT(false);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -481,8 +492,8 @@ struct Inventory {
|
||||
TR::LevelID id = level->id;
|
||||
switch (item->value) {
|
||||
case 0 : nextLevel = passportSlots[slot]; break;
|
||||
case 1 : nextLevel = id == TR::LVL_TR1_TITLE ? TR::LVL_TR1_1 : (id == TR::LVL_TR2_TITLE ? TR::LVL_TR2_WALL : id); break;
|
||||
case 2 : nextLevel = level->isTitle() ? TR::LVL_MAX : level->titleId(); break;
|
||||
case 1 : nextLevel = level->isTitle() ? level->getStartId() : id; break;
|
||||
case 2 : nextLevel = level->isTitle() ? TR::LVL_MAX : level->getTitleId(); break;
|
||||
}
|
||||
|
||||
if (nextLevel != TR::LVL_MAX) {
|
||||
@@ -545,10 +556,7 @@ struct Inventory {
|
||||
}
|
||||
|
||||
if (item->type == TR::Entity::INV_HOME && phaseChoose == 1.0f && key == cAction) {
|
||||
if (level->version & TR::VER_TR1)
|
||||
nextLevel = TR::LVL_TR1_GYM;
|
||||
if (level->version & TR::VER_TR2)
|
||||
nextLevel = TR::LVL_TR2_ASSAULT;
|
||||
nextLevel = level->getHomeId();
|
||||
toggle();
|
||||
}
|
||||
|
||||
|
22
src/lara.h
22
src/lara.h
@@ -411,6 +411,9 @@ 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 (level->extra.laraSkin > -1)
|
||||
level->entities[entity].modelIndex = level->extra.laraSkin + 1;
|
||||
|
||||
jointChest = 7;
|
||||
jointHead = 14;
|
||||
rangeChest = vec4(-0.40f, 0.40f, -0.90f, 0.90f) * PI;
|
||||
@@ -445,7 +448,7 @@ struct Lara : Character {
|
||||
}
|
||||
|
||||
if (level->extra.braid > -1)
|
||||
braid = new Braid(this, (level->version & TR::VER_TR2) ? vec3(0.0f, -16.0f, -48.0f) : vec3(-4.0f, 24.0f, -48.0f));
|
||||
braid = new Braid(this, (level->version & (TR::VER_TR2 | TR::VER_TR3)) ? vec3(0.0f, -16.0f, -48.0f) : vec3(-4.0f, 24.0f, -48.0f));
|
||||
#ifdef _DEBUG
|
||||
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, STAND_ONWATER); // gym (pool)
|
||||
//reset(0, vec3(74858, 3072, 20795), 0); // level 1 (dart)
|
||||
@@ -1382,7 +1385,8 @@ struct Lara : Character {
|
||||
case TR::Effect::MESH_SWAP_1 :
|
||||
case TR::Effect::MESH_SWAP_2 :
|
||||
case TR::Effect::MESH_SWAP_3 : Character::cmdEffect(fx);
|
||||
case 26 : break; // TR2 TODO reset_hair
|
||||
case 26 : break; // TODO TR2 reset_hair
|
||||
case 32 : break; // TODO TR3 footprint
|
||||
default : LOG("unknown effect command %d (anim %d)\n", fx, animation.index); ASSERT(false);
|
||||
}
|
||||
}
|
||||
@@ -1436,7 +1440,7 @@ struct Lara : Character {
|
||||
}
|
||||
|
||||
virtual void hit(float damage, Controller *enemy = NULL, TR::HitType hitType = TR::HIT_DEFAULT) {
|
||||
if (dozy) return;
|
||||
if (dozy || level->isCutsceneLevel()) return;
|
||||
|
||||
if (health <= 0.0f) return;
|
||||
|
||||
@@ -1694,7 +1698,7 @@ struct Lara : Character {
|
||||
if (level->state.tracks[track].once) {
|
||||
timer += Core::deltaTime;
|
||||
if (timer > 3.0f)
|
||||
game->loadLevel(level->titleId());
|
||||
game->loadLevel(level->getTitleId());
|
||||
} else {
|
||||
if (state != STATE_WATER_OUT)
|
||||
return 0;
|
||||
@@ -1980,7 +1984,7 @@ struct Lara : Character {
|
||||
else
|
||||
flags.active |= info.trigInfo.mask;
|
||||
|
||||
if ( (flags.active == TR::ACTIVE) || (((level->version & TR::VER_TR2)) && flags.active) ) {
|
||||
if ( (flags.active == TR::ACTIVE) || (((level->version & (TR::VER_TR2 | TR::VER_TR3))) && flags.active) ) {
|
||||
flags.once |= info.trigInfo.once;
|
||||
game->playTrack(track);
|
||||
} else
|
||||
@@ -1995,7 +1999,7 @@ struct Lara : Character {
|
||||
if (!(level->state.secrets & (1 << cmd.args))) {
|
||||
level->state.secrets |= 1 << cmd.args;
|
||||
if (!game->playSound(TR::SND_SECRET, pos))
|
||||
game->playTrack(TR::TRACK_SECRET);
|
||||
game->playTrack(TR::TRACK_TR1_SECRET);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2379,7 +2383,8 @@ struct Lara : Character {
|
||||
|
||||
if (state == STATE_FORWARD_JUMP || state == STATE_UP_JUMP || state == STATE_BACK_JUMP || state == STATE_LEFT_JUMP || state == STATE_RIGHT_JUMP || state == STATE_FALL || state == STATE_REACH || state == STATE_SLIDE || state == STATE_SLIDE_BACK) {
|
||||
game->waterDrop(pos, 256.0f, 0.2f);
|
||||
game->addEntity(TR::Entity::WATER_SPLASH, getRoomIndex(), pos);
|
||||
if (level->extra.waterSplash > -1)
|
||||
game->addEntity(TR::Entity::WATER_SPLASH, getRoomIndex(), pos);
|
||||
pos.y += 100.0f;
|
||||
angle.x = -45.0f * DEG2RAD;
|
||||
return animation.setAnim(ANIM_WATER_FALL); // TODO: wronng animation
|
||||
@@ -2388,7 +2393,8 @@ struct Lara : Character {
|
||||
if (state == STATE_SWAN_DIVE || state == STATE_FAST_DIVE) {
|
||||
angle.x = -PI * 0.5f;
|
||||
game->waterDrop(pos, 128.0f, 0.2f);
|
||||
game->addEntity(TR::Entity::WATER_SPLASH, getRoomIndex(), pos);
|
||||
if (level->extra.waterSplash > -1)
|
||||
game->addEntity(TR::Entity::WATER_SPLASH, getRoomIndex(), pos);
|
||||
return STATE_DIVE;
|
||||
}
|
||||
|
||||
|
64
src/level.h
64
src/level.h
@@ -64,15 +64,19 @@ struct Level : IGame {
|
||||
strcat(buf, "level/");
|
||||
if (level.version & TR::VER_TR2)
|
||||
strcat(buf, "2/");
|
||||
if (level.version & TR::VER_TR3)
|
||||
strcat(buf, "3/");
|
||||
strcat(buf, TR::LEVEL_INFO[id].name);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
strcat(buf, ".PSX");
|
||||
#else
|
||||
switch (level.version) {
|
||||
case TR::VER_TR1_PC : strcat(buf, ".PHD"); break;
|
||||
case TR::VER_TR1_PSX : strcat(buf, ".PSX"); break;
|
||||
case TR::VER_TR2_PC : strcat(buf, ".TR2"); break;
|
||||
case TR::VER_TR2_PSX : strcat(buf, ".PSX"); break;
|
||||
case TR::VER_TR2_PC :
|
||||
case TR::VER_TR3_PC : strcat(buf, ".TR2"); break;
|
||||
case TR::VER_TR1_PSX :
|
||||
case TR::VER_TR2_PSX :
|
||||
case TR::VER_TR3_PSX : strcat(buf, ".PSX"); break;
|
||||
}
|
||||
#endif
|
||||
new Stream(buf, loadAsync);
|
||||
@@ -85,7 +89,7 @@ struct Level : IGame {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
loadLevel(level.id == TR::LVL_TR1_10C || level.id == TR::LVL_TR2_HOUSE ? level.titleId() : TR::LevelID(level.id + 1));
|
||||
loadLevel(level.isEnd() ? level.getTitleId() : TR::LevelID(level.id + 1));
|
||||
}
|
||||
|
||||
virtual void saveGame(int slot) {
|
||||
@@ -468,12 +472,12 @@ struct Level : IGame {
|
||||
if (a == -1) return NULL;
|
||||
|
||||
TR::SoundInfo &b = level.soundsInfo[a];
|
||||
if (b.chance == 0 || (rand() & 0x7fff) <= b.chance) {
|
||||
int index = b.offset + rand() % b.flags.count;
|
||||
float volume = (float)b.volume / 0x7FFF;
|
||||
float pitch = b.flags.pitch ? (0.9f + randf() * 0.2f) : 1.0f;
|
||||
if (b.chance == 0 || randf() <= b.chance) {
|
||||
int index = b.index + rand() % b.flags.count;
|
||||
float volume = b.volume;
|
||||
float pitch = 1.0f + (b.flags.pitch ? ((randf() - 0.5f) * b.pitch) : 0.0f);
|
||||
|
||||
if (level.version == TR::VER_TR2_PSX) // fix 8 kHz VAG in PSX TR2
|
||||
if (level.version == TR::VER_TR2_PSX) // fix for 8 kHz VAG in PSX TR2
|
||||
pitch *= 8000.0f / 11025.0f;
|
||||
|
||||
if (!(flags & Sound::MUSIC)) {
|
||||
@@ -541,6 +545,12 @@ struct Level : IGame {
|
||||
case TR::VER_TR2_PSX :
|
||||
sprintf(title, "audio/2/track_%02d.ogg", int(level.remapTrack(track)));
|
||||
break;
|
||||
case TR::VER_TR3_PC :
|
||||
case TR::VER_TR3_PSX :
|
||||
#ifndef __EMSCRIPTEN__
|
||||
playAsync(Sound::openWAD(NULL, track), this);
|
||||
#endif
|
||||
return;
|
||||
default : return;
|
||||
}
|
||||
|
||||
@@ -588,9 +598,7 @@ struct Level : IGame {
|
||||
// init sounds
|
||||
//sndSoundtrack = Sound::play(Sound::openWAD("05_Lara's_Themes.wav"), vec3(0.0f), 1, 1, Sound::Flags::LOOP);
|
||||
|
||||
sndUnderwater = playSound(TR::SND_UNDERWATER, vec3(0.0f), Sound::LOOP | Sound::MUSIC);
|
||||
if (sndUnderwater)
|
||||
sndUnderwater->volume = sndUnderwater->volumeTarget = 0.0f;
|
||||
sndUnderwater = NULL;
|
||||
|
||||
for (int i = 0; i < level.soundSourcesCount; i++) {
|
||||
TR::SoundSource &src = level.soundSources[i];
|
||||
@@ -919,7 +927,7 @@ struct Level : IGame {
|
||||
// repack texture tiles
|
||||
Atlas *tiles = new Atlas(level.objectTexturesCount + level.spriteTexturesCount + UI::BAR_MAX, &level, fillCallback);
|
||||
// add textures
|
||||
int texIdx = (level.version == TR::VER_TR1_PSX || level.version == TR::VER_TR2_PSX) ? 256 : 0; // skip palette color for PSX version
|
||||
int texIdx = (level.version & TR::VER_PSX) ? 256 : 0; // skip palette color for PSX version
|
||||
for (int i = texIdx; i < level.objectTexturesCount; i++) {
|
||||
TR::ObjectTexture &t = level.objectTextures[i];
|
||||
int16 tx = (t.tile.index % 4) * 256;
|
||||
@@ -1033,7 +1041,12 @@ struct Level : IGame {
|
||||
|
||||
//Animation anim(&level, &level.models[level.extra.sky]);
|
||||
|
||||
Basis b = Basis(quat(vec3(1, 0, 0), PI * 0.5f), vec3(0));
|
||||
// TODO TR2 TR3 use animation frame to get skydome rotation
|
||||
Basis b;
|
||||
if (level.version & TR::VER_TR2)
|
||||
b = Basis(quat(vec3(1, 0, 0), PI * 0.5f), vec3(0));
|
||||
else
|
||||
b = Basis(quat(0, 0, 0, 1), vec3(0));
|
||||
|
||||
Core::setDepthTest(false);
|
||||
setShader(Core::pass, Shader::FLASH, false, false);
|
||||
@@ -1223,7 +1236,7 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (level.isCutsceneLevel() && (lara->health > 0.0f && !sndSoundtrack))
|
||||
if (level.isCutsceneLevel() && (lara->health > 0.0f && !sndSoundtrack && TR::LEVEL_INFO[level.id].ambientTrack != TR::NO_TRACK))
|
||||
return;
|
||||
|
||||
if (Input::state[cInventory] && !level.isTitle()) {
|
||||
@@ -1264,7 +1277,15 @@ struct Level : IGame {
|
||||
|
||||
Controller::clearInactive();
|
||||
|
||||
sndChanged = camera->isUnderwater() ? sndUnderwater : sndSoundtrack;
|
||||
if (camera->isUnderwater()) {
|
||||
if (!sndUnderwater) {
|
||||
sndUnderwater = playSound(TR::SND_UNDERWATER, vec3(0.0f), Sound::LOOP | Sound::MUSIC);
|
||||
if (sndUnderwater)
|
||||
sndUnderwater->volume = sndUnderwater->volumeTarget = 0.0f;
|
||||
}
|
||||
sndChanged = sndUnderwater;
|
||||
} else
|
||||
sndChanged = sndSoundtrack;
|
||||
}
|
||||
|
||||
if (sndChanged != sndCurrent) {
|
||||
@@ -1450,12 +1471,11 @@ struct Level : IGame {
|
||||
int roomsCount = 0;
|
||||
|
||||
getVisibleRooms(roomsList, roomsCount, TR::NO_ROOM, roomIndex, vec4(-1.0f, -1.0f, 1.0f, 1.0f), water);
|
||||
// show all rooms
|
||||
/*
|
||||
for (int i = 0; i < level.roomsCount; i++)
|
||||
roomsList[i] = i;
|
||||
roomsCount = level.roomsCount;
|
||||
*/
|
||||
if (level.isCutsceneLevel()) {
|
||||
for (int i = 0; i < level.roomsCount; i++)
|
||||
roomsList[i] = i;
|
||||
roomsCount = level.roomsCount;
|
||||
}
|
||||
|
||||
if (water && waterCache) {
|
||||
for (int i = 0; i < roomsCount; i++)
|
||||
|
21
src/mesh.h
21
src/mesh.h
@@ -303,7 +303,7 @@ struct MeshBuilder {
|
||||
int y = m.y;
|
||||
int z = m.z - room.info.z;
|
||||
int d = m.rotation.value / 0x4000;
|
||||
buildMesh(!transp, mesh, level, indices, vertices, iCount, vCount, vStartRoom, 0, x, y, z, d);
|
||||
buildMesh(!transp, mesh, level, indices, vertices, iCount, vCount, vStartRoom, 0, x, y, z, d, m.color);
|
||||
}
|
||||
range.geometry[transp].iCount = iCount - range.geometry[transp].iStart;
|
||||
}
|
||||
@@ -326,6 +326,8 @@ struct MeshBuilder {
|
||||
int vStartModel = vCount;
|
||||
aCount++;
|
||||
|
||||
TR::Color32 COLOR_WHITE = { 255, 255, 255, 255 };
|
||||
|
||||
for (int i = 0; i < level.modelsCount; i++) {
|
||||
TR::Model &model = level.models[i];
|
||||
ModelRange &range = models[i];
|
||||
@@ -339,9 +341,9 @@ struct MeshBuilder {
|
||||
if (!index && model.mStart + j > 0) continue;
|
||||
|
||||
TR::Mesh &mesh = level.meshes[index];
|
||||
bool opaque = buildMesh(true, mesh, level, indices, vertices, iCount, vCount, vStartModel, j, 0, 0, 0, 0);
|
||||
bool opaque = buildMesh(true, mesh, level, indices, vertices, iCount, vCount, vStartModel, j, 0, 0, 0, 0, COLOR_WHITE);
|
||||
if (!opaque)
|
||||
buildMesh(false, mesh, level, indices, vertices, iCount, vCount, vStartModel, j, 0, 0, 0, 0);
|
||||
buildMesh(false, mesh, level, indices, vertices, iCount, vCount, vStartModel, j, 0, 0, 0, 0, COLOR_WHITE);
|
||||
TR::Entity::fixOpaque(model.type, opaque);
|
||||
range.opaque &= opaque;
|
||||
}
|
||||
@@ -662,7 +664,8 @@ struct MeshBuilder {
|
||||
TR::Room::Data::Vertex &v = d.vertices[f.vertices[k]];
|
||||
vertices[vCount].coord = { v.vertex.x, v.vertex.y, v.vertex.z, 0 };
|
||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||
vertices[vCount].color = { 255, 255, 255, intensity(v.lighting) };
|
||||
TR::Color32 c = v.color;
|
||||
vertices[vCount].color = { c.b, c.g, c.r, intensity(v.lighting) };
|
||||
vCount++;
|
||||
}
|
||||
}
|
||||
@@ -688,7 +691,8 @@ struct MeshBuilder {
|
||||
auto &v = d.vertices[f.vertices[k]];
|
||||
vertices[vCount].coord = { v.vertex.x, v.vertex.y, v.vertex.z, 0 };
|
||||
vertices[vCount].normal = { n.x, n.y, n.z, 0 };
|
||||
vertices[vCount].color = { 255, 255, 255, intensity(v.lighting) };
|
||||
TR::Color32 c = v.color;
|
||||
vertices[vCount].color = { c.b, c.g, c.r, intensity(v.lighting) };
|
||||
vCount++;
|
||||
}
|
||||
}
|
||||
@@ -696,7 +700,7 @@ struct MeshBuilder {
|
||||
return isOpaque;
|
||||
}
|
||||
|
||||
bool buildMesh(bool opaque, const TR::Mesh &mesh, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir) {
|
||||
bool buildMesh(bool opaque, const TR::Mesh &mesh, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir, const TR::Color32 &color) {
|
||||
TR::Color24 COLOR_WHITE = { 255, 255, 255 };
|
||||
bool isOpaque = true;
|
||||
|
||||
@@ -711,6 +715,9 @@ struct MeshBuilder {
|
||||
continue;
|
||||
|
||||
TR::Color32 c = f.flags.color ? level.getColor(f.flags.texture) : COLOR_WHITE;
|
||||
c.r = int(( (c.r / 255.0f) * (color.b / 255.0f) ) * 255.0f);
|
||||
c.g = int(( (c.g / 255.0f) * (color.g / 255.0f) ) * 255.0f);
|
||||
c.b = int(( (c.b / 255.0f) * (color.r / 255.0f) ) * 255.0f);
|
||||
|
||||
addQuad(indices, iCount, vCount, vStart, vertices, &t,
|
||||
mesh.vertices[f.vertices[0]].coord,
|
||||
@@ -829,7 +836,7 @@ struct MeshBuilder {
|
||||
v.param = { range, frame, 0, 0 };
|
||||
}
|
||||
|
||||
if ((level->version == TR::VER_TR1_PSX || level->version == TR::VER_TR2_PSX) && !triangle)
|
||||
if (((level->version & TR::VER_PSX)) && !triangle)
|
||||
swap(vertices[vCount + 2].texCoord, vertices[vCount + 3].texCoord);
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#define H_SOUND
|
||||
|
||||
#define DECODE_VAG
|
||||
//#define DECODE_ADPCM
|
||||
#define DECODE_ADPCM
|
||||
//#define DECODE_MP3
|
||||
#define DECODE_OGG
|
||||
|
||||
@@ -210,7 +210,7 @@ namespace Sound {
|
||||
|
||||
if (seek % block == 0) {
|
||||
for (int i = 0; i < channels; i++) {
|
||||
char index;
|
||||
uint8 index;
|
||||
stream->read(index);
|
||||
channel[i].c1 = coeff1[index];
|
||||
channel[i].c2 = coeff2[index];
|
||||
@@ -679,7 +679,7 @@ namespace Sound {
|
||||
}
|
||||
}
|
||||
|
||||
Stream *openWAD(const char *name) {
|
||||
Stream *openWAD(const char *name, int index = -1) {
|
||||
Stream *stream = new Stream("cdaudio.wad");
|
||||
if (stream->size) {
|
||||
struct Item {
|
||||
@@ -690,7 +690,7 @@ namespace Sound {
|
||||
|
||||
for (int i = 0; i < 130; i++) {
|
||||
stream->read(entity);
|
||||
if (strcmp(name, entity.name) == 0) {
|
||||
if ((name && strcmp(name, entity.name) == 0) || index == i) {
|
||||
stream->setPos(entity.offset);
|
||||
return stream;
|
||||
}
|
||||
@@ -701,6 +701,7 @@ namespace Sound {
|
||||
}
|
||||
|
||||
Sample* play(Stream *stream, const vec3 &pos, float volume = 1.0f, float pitch = 0.0f, int flags = 0, int id = - 1) {
|
||||
ASSERT(pitch >= 0.0f);
|
||||
if (!stream) return NULL;
|
||||
if (volume > 0.001f) {
|
||||
if (!(flags & (FLIPPED | UNFLIPPED | MUSIC)) && (flags & PAN)) {
|
||||
|
@@ -166,15 +166,15 @@ struct Texture {
|
||||
}
|
||||
}
|
||||
|
||||
struct Color24 {
|
||||
uint8 r, g, b;
|
||||
};
|
||||
|
||||
struct Color32 {
|
||||
uint8 r, g, b, a;
|
||||
};
|
||||
|
||||
static Texture* LoadPCX(Stream &stream) {
|
||||
struct Color24 {
|
||||
uint8 r, g, b;
|
||||
};
|
||||
|
||||
struct Color32 {
|
||||
uint8 r, g, b, a;
|
||||
};
|
||||
|
||||
struct PCX {
|
||||
uint8 magic;
|
||||
uint8 version;
|
||||
@@ -240,6 +240,47 @@ struct Texture {
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
static Texture* LoadBMP(Stream &stream) {
|
||||
int32 offset, width, height;
|
||||
stream.seek(10);
|
||||
stream.read(offset);
|
||||
stream.seek(4);
|
||||
stream.read(width);
|
||||
stream.read(height);
|
||||
stream.seek(offset - stream.pos);
|
||||
Color24 *data24 = new Color24[width * height];
|
||||
Color32 *data32 = new Color32[width * height];
|
||||
stream.raw(data24, width * height * sizeof(Color24));
|
||||
|
||||
Color32 *dst = data32;
|
||||
for (int y = 0; y < height; y++) {
|
||||
Color24 *src = data24 + (height - y - 1) * width;
|
||||
for (int x = 0; x < width; x++) {
|
||||
dst->r = src->b;
|
||||
dst->g = src->g;
|
||||
dst->b = src->r;
|
||||
dst->a = 255;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
Texture *tex = new Texture(width, height, Texture::RGBA, false, data32);
|
||||
|
||||
delete[] data24;
|
||||
delete[] data32;
|
||||
return tex;
|
||||
}
|
||||
|
||||
static Texture* Load(Stream &stream) {
|
||||
uint16 magic;
|
||||
stream.read(magic);
|
||||
stream.seek(-int(sizeof(magic)));
|
||||
if (magic == 0x4D42)
|
||||
return LoadBMP(stream);
|
||||
return LoadPCX(stream);
|
||||
}
|
||||
};
|
||||
|
||||
#define ATLAS_BORDER 8
|
||||
@@ -349,7 +390,7 @@ struct Atlas {
|
||||
|
||||
Texture* pack() {
|
||||
// TODO TR2 fix CUT2 AV
|
||||
width = 2048;//nextPow2(int(sqrtf(float(size))));
|
||||
width = 4096;//nextPow2(int(sqrtf(float(size))));
|
||||
height = 2048;//(width * width / 2 > size) ? (width / 2) : width;
|
||||
// sort
|
||||
int *indices = new int[tilesCount];
|
||||
|
@@ -1358,7 +1358,8 @@ struct Waterfall : Controller {
|
||||
vec2 p = (vec2(randf(), randf()) * 2.0f - 1.0f) * (512.0f - dropRadius);
|
||||
vec3 dropPos = pos + vec3(p.x, 0.0f, p.y);
|
||||
game->waterDrop(dropPos, dropRadius, dropStrength);
|
||||
game->addEntity(TR::Entity::WATER_SPLASH, getRoomIndex(), dropPos);
|
||||
if (level->extra.waterSplash > -1)
|
||||
game->addEntity(TR::Entity::WATER_SPLASH, getRoomIndex(), dropPos);
|
||||
}
|
||||
|
||||
#undef SPLASH_TIMESTEP
|
||||
|
Reference in New Issue
Block a user