1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-16 01:54:38 +02:00

#23 colored lights; fix water plane level; #3 temporary fix shallow water; #15 fix floor data parser for TR3; #11 fix NPOT textures loader for bmp; font shading;

This commit is contained in:
XProger
2017-11-25 18:45:43 +03:00
parent aaabdde6e9
commit a927da8d73
14 changed files with 306 additions and 118 deletions

View File

@@ -396,7 +396,7 @@ struct WaterCache {
minZ = min(minZ, z);
maxX = max(maxX, x);
maxZ = max(maxZ, z);
posY = s.ceiling * 256;
posY = level->rooms[s.roomAbove].waterLevel;
if (s.roomBelow != TR::NO_ROOM)
caust = s.roomBelow;
}
@@ -417,8 +417,10 @@ struct WaterCache {
bool hasWater = s.roomAbove != TR::NO_ROOM && !level->rooms[s.roomAbove].flags.water;
if (hasWater) {
TR::Room &rt = level->rooms[s.roomAbove];
TR::Room::Sector &st = rt.sectors[x * rt.zSectors + z];
hasWater = s.ceiling > st.ceiling;
int xt = int(r.info.x + x * 1024 - rt.info.x) / 1024;
int zt = int(r.info.z + z * 1024 - rt.info.z) / 1024;
TR::Room::Sector &st = rt.sectors[xt * rt.zSectors + zt];
hasWater = s.ceiling > st.ceiling; // TODO fix for LEVEL10A, use slant
}
m[(x - minX) + w * (z - minZ)] = hasWater ? 0xF800 : 0;

View File

@@ -59,6 +59,17 @@ struct Character : Controller {
updateZone();
}
virtual int getRoomIndex() const {
int index = Controller::getRoomIndex();
TR::Level::FloorInfo info;
getFloorInfo(index, pos, info);
if (level->rooms[index].flags.water && info.roomAbove != TR::NO_ROOM && (info.floor - level->rooms[index].info.yTop) <= 512)
return info.roomAbove;
return index;
}
bool updateZone() {
int dx, dz;
TR::Room::Sector &s = level->getSector(getRoomIndex(), int(pos.x), int(pos.z), dx, dz);

View File

@@ -372,7 +372,7 @@ struct Controller {
break;
case TR::FloorData::CLIMB :
info.climb = (*fd++).data; // climb mask
info.climb = cmd.sub; // climb mask
break;
case 0x07 :
@@ -386,7 +386,7 @@ struct Controller {
case 0x0F :
case 0x10 :
case 0x11 :
case 0x12 : break; // TODO TR3 triangulation
case 0x12 : fd++; break; // TODO TR3 triangulation
case 0x13 : break; // TODO TR3 monkeyswing
@@ -934,17 +934,19 @@ struct Controller {
float maxAtt = 0.0f;
if (room.flags.sky) { // TODO trace rooms up for sun light, add direct light projection
sunLight.x = int32(center.x);
sunLight.y = int32(center.y) - 8192;
sunLight.z = int32(center.z);
targetLight = &sunLight;
sunLight.x = int32(center.x);
sunLight.y = int32(center.y) - 8192;
sunLight.z = int32(center.z);
sunLight.color = TR::Color32(255, 255, 255, 255);
sunLight.radius = 1000 * 1024;
targetLight = &sunLight;
} else {
for (int i = 0; i < room.lightsCount; i++) {
TR::Room::Light &light = room.lights[i];
if (light.intensity > 0x1FFF) continue;
if ((light.color.r | light.color.g | light.color.b) == 0) continue;
vec3 dir = vec3(float(light.x), float(light.y), float(light.z)) - center;
float att = max(0.0f, 1.0f - dir.length2() / float(light.radius) / float(light.radius)) * (1.0f - intensityf(light.intensity));
float att = max(0.0f, 1.0f - dir.length2() / float(light.radius) / float(light.radius));
if (att > maxAtt) {
maxAtt = att;
@@ -962,7 +964,7 @@ struct Controller {
}
vec3 tpos = vec3(float(targetLight->x), float(targetLight->y), float(targetLight->z));
vec4 tcolor = vec4(vec3(1.0f - intensityf(targetLight->intensity)), float(targetLight->radius));
vec4 tcolor = vec4(vec3(targetLight->color.r, targetLight->color.g, targetLight->color.b) * (1.0f / 255.0f), float(targetLight->radius));
if (lerp) {
float t = Core::deltaTime * 2.0f;

View File

@@ -335,7 +335,7 @@ namespace Core {
#define MAX_RENDER_BUFFERS 32
#define MAX_CONTACTS 15
#define MAX_ANIM_TEX_RANGES 32
#define MAX_ANIM_TEX_OFFSETS 130
#define MAX_ANIM_TEX_OFFSETS 170
struct Shader;
struct Texture;
@@ -367,7 +367,8 @@ struct Vertex {
short4 normal; // xyz - vertex normal, w - unused
short4 texCoord; // xy - texture coordinates, zw - trapezoid warping
ubyte4 param; // xy - anim tex range and frame index, zw - unused
ubyte4 color; // xyz - color, w - intensity
ubyte4 color; // for non-textured geometry
ubyte4 light; // xyz - color, w - use premultiplied alpha
};
#ifdef PROFILE

View File

@@ -474,9 +474,8 @@ namespace Debug {
for (int i = 0; i < level.roomsCount; i++)
for (int j = 0; j < level.rooms[i].lightsCount; j++) {
TR::Room::Light &l = level.rooms[i].lights[j];
float a = 1.0f - intensityf(l.intensity);
vec3 p = vec3(float(l.x), float(l.y), float(l.z));
vec4 color = vec4(a, a, a, 1);
vec4 color = vec4(l.color.r, l.color.g, l.color.b, 255) * (1.0f / 255.0f);
// if (i == room) color.x = color.z = 0;
Debug::Draw::point(p, color);
@@ -485,7 +484,7 @@ namespace Debug {
Debug::Draw::sphere(p, float(l.radius), color);
}
vec4 color = vec4(lara->mainLightColor.x, 0.0f, 0.0f, 1.0f);
vec4 color = vec4(lara->mainLightColor.xyz, 1.0f);
Debug::Draw::point(lara->mainLightPos, color);
Debug::Draw::sphere(lara->mainLightPos, lara->mainLightColor.w, color);
}
@@ -658,9 +657,11 @@ namespace Debug {
const char *getEntityName(const TR::Level &level, const TR::Entity &entity) {
if (entity.type < TR::Entity::TR1_TYPE_MAX)
return TR_TYPE_NAMES[entity.type - TR1_TYPES_START];
else
if (entity.type < TR::Entity::TR2_TYPE_MAX)
return TR_TYPE_NAMES[entity.type - TR2_TYPES_START + TR::Entity::TR1_TYPE_MAX + 1];
if (entity.type < TR::Entity::TR2_TYPE_MAX)
return TR_TYPE_NAMES[entity.type - TR2_TYPES_START + (TR::Entity::TR1_TYPE_MAX - TR1_TYPES_START) + 1];
if (entity.type < TR::Entity::TR3_TYPE_MAX)
return TR_TYPE_NAMES[entity.type - TR3_TYPES_START + (TR::Entity::TR1_TYPE_MAX - TR1_TYPES_START) + (TR::Entity::TR2_TYPE_MAX - TR2_TYPES_START) + 2];
return "UNKNOWN";
}

View File

@@ -485,11 +485,13 @@
E( __LARA_FLARE ) \
E( LARA_UPV ) \
E( VEHICLE_UPV ) \
E( UNUSED_TR3_13 ) \
E( VEHICLE_KAYAK ) \
E( __VEHICLE_BOAT ) \
E( VEHICLE_QUADBIKE ) \
E( VEHICLE_MINECART ) \
E( BIG_GUN ) \
E( HYDRO_PROPELLER ) \
E( ENEMY_TRIBESMAN_AXE ) \
E( ENEMY_TRIBESMAN_DART ) \
E( __ENEMY_DOG ) \
@@ -500,8 +502,60 @@
E( __ENEMY_CROW ) \
E( __ENEMY_TIGER ) \
E( ENEMY_VULTURE ) \
\
E( __TRAP_FLOOR = TR3_TYPES_START + 83 ) \
E( ASSAULT_TARGET ) \
E( ENEMY_CRAWLER_MUTANT_1 ) \
E( ENEMY_ALLIGATOR ) \
E( UNUSED_TR3_33 ) \
E( ENEMY_COMPSOGNATHUS ) \
E( ENEMY_LIZARD_MAN ) \
E( ENEMY_PUNA ) \
E( ENEMY_MERCENARY ) \
E( ENEMY_RAPTOR_HUNG ) \
E( ENEMY_RX_TECH_GUY_1 ) \
E( ENEMY_RX_TECH_GUY_2 ) \
E( ENEMY_ANTARC_DOG ) \
E( ENEMY_CRAWLER_MUTANT_2 ) \
E( UNUSED_TR3_43 ) \
E( ENEMY_TINNOS_WASP ) \
E( ENEMY_TINNOS_MONSTER ) \
E( ENEMY_BRUTE_MUTANT ) \
E( RESPAWN_TINNOS_WASP ) \
E( RESPAWN_RAPTOR ) \
E( ENEMY_WILLARD_SPIDER ) \
E( ENEMY_RX_TECH_FLAME_GUY ) \
E( ENEMY_LONDON_MERCENARY ) \
E( UNUSED_TR3_52 ) \
E( ENEMY_PUNK ) \
E( UNUSED_TR3_54 ) \
E( UNUSED_TR3_55 ) \
E( ENEMY_LONDON_GUARD ) \
E( ENEMY_SOPHIA ) \
E( CLEANER_ROBOT ) \
E( UNUSED_TR3_59 ) \
E( ENEMY_MILITARY_1 ) \
E( ENEMY_MILITARY_2 ) \
E( PRISONER ) \
E( ENEMY_MILITARY_3 ) \
E( GUN_TURRET ) \
E( ENEMY_DAM_GUARD ) \
E( TRIPWIRE ) \
E( ELECTRIC_WIRE ) \
E( KILLER_TRIPWIRE ) \
E( ENEMY_COBRA ) \
E( ENEMY_SHIVA ) \
E( ENEMY_MONKEY ) \
E( UNUSED_TR3_72 ) \
E( ENEMY_TONY ) \
E( AI_GUARD ) \
E( AI_AMBUSH ) \
E( AI_PATROL_1 ) \
E( AI_MODIFY ) \
E( AI_FOLLOW ) \
E( AI_PATROL_2 ) \
E( AI_PATH ) \
E( AI_CHECK ) \
E( UNUSED_TR3_82 ) \
E( __TRAP_FLOOR ) \
E( UNUSED_TR3_84 ) \
E( UNUSED_TR3_85 ) \
E( TRAP_SWING_THING ) \
@@ -564,7 +618,7 @@
E( __BRIDGE_2 ) \
E( __BRIDGE_3 ) \
E( __INV_PASSPORT ) \
E( __INV_COMPASS ) \
E( __INV_STOPWATCH ) \
E( __INV_HOME ) \
E( __CUT_4 ) \
E( __CUT_5 ) \
@@ -598,7 +652,7 @@
E( __MEDIKIT_BIG ) \
E( __FLARES ) \
E( __FLARE ) \
E( __CRYSTAL ) \
E( CRYSTAL_PICKUP ) \
E( __INV_DETAIL ) \
E( __INV_SOUND ) \
E( __INV_CONTROLS ) \
@@ -786,7 +840,11 @@
E( __EARTHQUAKE ) \
E( GUN_SHELL_1 ) \
E( GUN_SHELL_2 ) \
E( UNUSED_TR3_368 ) \
E( UNUSED_TR3_369 ) \
E( TINNOS_LIGHT_SHAFT ) \
E( UNUSED_TR3_371 ) \
E( UNUSED_TR3_372 ) \
E( ELECTRIC_SWITCH ) \
E( TR3_TYPE_MAX )
@@ -854,7 +912,9 @@ namespace TR {
FLIP_MAP ,
DRAW_RIGHTGUN ,
DRAW_LEFTGUN ,
FLICKER ,
SHOT_RIGHTGUN ,
SHOT_LEFTGUN ,
FLICKER = 16,
UNKNOWN ,
MESH_SWAP_1 ,
MESH_SWAP_2 ,
@@ -1112,6 +1172,7 @@ namespace TR {
struct { uint16 r:5, g:5, b:5, a:1; };
uint16 value;
Color32 getBGR() const { return Color32((b << 3) | (b >> 2), (g << 3) | (g >> 2), (r << 3) | (r >> 2), 255); }
operator Color24() const { return Color24((r << 3) | (r >> 2), (g << 3) | (g >> 2), (b << 3) | (b >> 2)); }
operator Color32() const { return Color32((r << 3) | (r >> 2), (g << 3) | (g >> 2), (b << 3) | (b >> 2), -a); }
};
@@ -1178,9 +1239,9 @@ namespace TR {
struct Vertex {
TR::Vertex vertex;
int16 lighting; // 0 (bright) .. 0x1FFF (dark)
int16 unused_lighting; // 0 (bright) .. 0x1FFF (dark)
uint16 attributes;
Color16 color;
Color32 color;
} *vertices;
Rectangle *rectangles;
@@ -1208,6 +1269,7 @@ namespace TR {
uint8 reverbType;
uint8 filter;
uint8 align;
uint32 waterLevel;
struct Portal {
uint16 roomIndex;
@@ -1239,19 +1301,15 @@ namespace TR {
struct Light {
int32 x, y, z;
uint16 intensity;
uint16 intensity2;
uint32 radius;
uint32 radius2;
Color32 color;
} *lights;
struct Mesh {
int32 x, y, z;
angle rotation;
Color16 color;
int16 intensity;
uint16 meshID;
Color32 color;
uint32 meshIndex; // index into static meshes array
} *meshes;
@@ -1263,7 +1321,7 @@ namespace TR {
union FloorData {
uint16 data;
struct Command {
uint16 func:8, sub:7, end:1;
uint16 func:5, tri:3, sub:7, end:1;
} cmd;
struct Slant {
int8 x:8, z:8;
@@ -1529,7 +1587,7 @@ namespace TR {
REMAP_3( BRIDGE_2 );
REMAP_3( BRIDGE_3 );
REMAP_3( INV_PASSPORT );
REMAP_3( INV_COMPASS );
REMAP_3( INV_STOPWATCH );
REMAP_3( INV_HOME );
REMAP_3( CUT_4 );
REMAP_3( CUT_5 );
@@ -1555,7 +1613,6 @@ namespace TR {
REMAP_3( MEDIKIT_BIG );
REMAP_3( FLARES );
REMAP_3( FLARE );
REMAP_3( CRYSTAL );
REMAP_3( INV_DETAIL );
REMAP_3( INV_SOUND );
REMAP_3( INV_CONTROLS );
@@ -1660,7 +1717,16 @@ namespace TR {
(type >= KEY_ITEM_1 && type <= KEY_ITEM_4) ||
(type == MEDIKIT_SMALL || type == MEDIKIT_BIG) ||
(type == SCION_PICKUP_QUALOPEC || type == SCION_PICKUP_DROP || type == SCION_PICKUP_HOLDER || type == LEADBAR) ||
(type >= SECRET_1 && type <= SECRET_3); // TODO: recheck all items
(type >= SECRET_1 && type <= SECRET_3) ||
(type == M16 || type == AMMO_M16) ||
(type == MP5 || type == AMMO_MP5) ||
(type == AUTOPISTOLS || type == AMMO_AUTOPISTOLS) ||
(type == DESERT_EAGLE || type == AMMO_DESERT_EAGLE) ||
(type == GRENADE || type == AMMO_GRENADE) ||
(type == ROCKET || type == AMMO_ROCKET) ||
(type == HARPOON || type == AMMO_HARPOON) ||
(type == FLARES || type == FLARE) ||
(type >= STONE_ITEM_1 || type <= STONE_ITEM_4);
}
bool isPickup() const {
@@ -3207,6 +3273,8 @@ namespace TR {
for (int i = 0; i < d.vCount; i++) {
Room::Data::Vertex &v = d.vertices[i];
uint16 lighting;
if (version == VER_TR2_PSX) {
union Compressed {
struct { uint32 lighting:8, attributes:8, z:5, y:5, x:5, w:1; };
@@ -3216,30 +3284,36 @@ namespace TR {
v.vertex.x = (comp.x << 10);
v.vertex.y = (comp.y << 8) + r.info.yTop;
v.vertex.z = (comp.z << 10);
v.lighting = comp.lighting;
lighting = comp.lighting;
v.attributes = comp.attributes;
v.color.value = 0xFFFF;
ASSERT(comp.w == 0);
} else {
stream.read(v.vertex.x);
stream.read(v.vertex.y);
stream.read(v.vertex.z);
stream.read(v.lighting);
stream.read(lighting);
if (version == VER_TR2_PC || version == VER_TR3_PC)
stream.read(v.attributes);
if (version == VER_TR2_PC)
stream.read(v.lighting); // real lighting value
stream.read(lighting); // real lighting value
if (version == VER_TR3_PC)
stream.read(v.color.value);
else
v.color.value = 0xFFFF;
if (version == VER_TR3_PC) {
Color16 color;
stream.read(color.value);
v.color = color.getBGR();
}
}
if (version & VER_PSX)
v.lighting = 0x1FFF - (v.lighting << 5); // convert vertex luminance from PSX to PC format
lighting = 0x1FFF - (lighting << 5); // convert vertex luminance from PSX to PC format
if ((version & VER_VERSION) < VER_TR3) { // lighting to color conversion
int value = clamp((lighting > 0x1FFF) ? 255 : (255 - (lighting >> 5)), 0, 255);
v.color.r = v.color.g = v.color.b = value;
v.color.a = 255;
}
}
if (version == VER_TR2_PSX)
@@ -3337,22 +3411,29 @@ namespace TR {
stream.read(light.y);
stream.read(light.z);
uint16 intensity;
if (version == VER_TR3_PC)
stream.read(light.color);
if (version == VER_TR1_PSX) {
uint32 intensity;
light.intensity = stream.read(intensity);
} else
stream.read(light.intensity);
stream.read(intensity);
if (version == VER_TR1_PSX)
stream.seek(2);
if (version & (VER_TR2 | VER_TR3))
stream.read(light.intensity2);
stream.seek(2); // intensity2
stream.read(light.radius);
if (version & VER_TR2)
stream.read(light.radius2);
stream.seek(4); // radius2
if ((version & VER_VERSION) < VER_TR3) {
int value = 2555 - clamp((intensity > 0x1FFF) ? 0 : (intensity >> 5), 0, 255);
light.color.r = light.color.g = light.color.b = value;
light.color.a = 0;
}
light.radius *= 2;
}
@@ -3365,11 +3446,23 @@ namespace TR {
stream.read(m.y);
stream.read(m.z);
stream.read(m.rotation);
if (version & (VER_TR2 | VER_TR3))
stream.read(m.color.value);
if (!(version & VER_TR3))
m.color.value = 0xFFFF;
stream.read(m.intensity);
if (version & VER_TR3) {
Color16 color;
stream.read(color.value);
m.color = color.getBGR();
}
if (version & VER_TR2)
stream.seek(2);
uint16 intensity;
stream.read(intensity);
if ((version & VER_VERSION) < VER_TR3) {
int value = clamp((intensity > 0x1FFF) ? 255 : (255 - (intensity >> 5)), 0, 255);
m.color.r = m.color.g = m.color.b = value;
m.color.a = 0;
}
stream.read(m.meshID);
if (version == VER_TR1_PSX)
stream.seek(2); // just an align for PSX version

View File

@@ -766,7 +766,7 @@ struct Inventory {
sprintf(buf, "%d %c", item->count, spec);
for (int i = 0; buf[i] != ' '; i++)
buf[i] -= 47;
UI::textOut(pos, buf, UI::aRight, width);
UI::textOut(pos, buf, UI::aRight, width, UI::SHADE_NONE);
}
}
@@ -1071,13 +1071,13 @@ struct Inventory {
UI::textOut(vec2( 0, 32), pageTitle[page], UI::aCenter, UI::width);
if (canFlipPage(-1)) {
UI::textOut(vec2(16, 32), "[", UI::aLeft, UI::width);
UI::textOut(vec2( 0, 32), "[", UI::aRight, UI::width - 20);
UI::textOut(vec2(16, 32), "[", UI::aLeft, UI::width, UI::SHADE_NONE);
UI::textOut(vec2( 0, 32), "[", UI::aRight, UI::width - 20, UI::SHADE_NONE);
}
if (canFlipPage(1)) {
UI::textOut(vec2(16, 480 - 16), "]", UI::aLeft, UI::width);
UI::textOut(vec2(0, 480 - 16), "]", UI::aRight, UI::width - 20);
UI::textOut(vec2(16, 480 - 16), "]", UI::aLeft, UI::width, UI::SHADE_NONE);
UI::textOut(vec2(0, 480 - 16), "]", UI::aRight, UI::width - 20, UI::SHADE_NONE);
}
if (index == targetIndex)

View File

@@ -949,7 +949,7 @@ struct Lara : Character {
}
void updateWeapon() {
if (level->cutEntity > -1) return;
if (level->isCutsceneLevel()) return;
if (wpnNext != Weapon::EMPTY && emptyHands()) {
wpnSet(wpnNext);
@@ -981,13 +981,8 @@ struct Lara : Character {
if (isRifle) break;
}
for (int i = 0; i < 2; i++) {
for (int i = 0; i < 2; i++)
arms[i].animation.update();
arms[i].shotTimer += Core::deltaTime;
float intensity = clamp((0.1f - arms[i].shotTimer) * 20.0f, EPS, 1.0f);
Core::lightColor[1 + i] = FLASH_LIGHT_COLOR * vec4(intensity, intensity, intensity, 1.0f / sqrtf(intensity));
}
if (isRifle)
animateShotgun();
@@ -1382,6 +1377,8 @@ struct Lara : Character {
case TR::Effect::LARA_HANDSFREE : break;//meshSwap(1, level->extra.weapons[wpnCurrent], BODY_LEG_L1 | BODY_LEG_R1); break;
case TR::Effect::DRAW_RIGHTGUN : drawGun(true); break;
case TR::Effect::DRAW_LEFTGUN : drawGun(false); break;
case TR::Effect::SHOT_RIGHTGUN : arms[0].shotTimer = 0; break;
case TR::Effect::SHOT_LEFTGUN : arms[1].shotTimer = 0; break;
case TR::Effect::MESH_SWAP_1 :
case TR::Effect::MESH_SWAP_2 :
case TR::Effect::MESH_SWAP_3 : Character::cmdEffect(fx);
@@ -1616,6 +1613,7 @@ struct Lara : Character {
int goUnderwater() {
angle.x = -PI * 0.25f;
game->waterDrop(pos, 256.0f, 0.2f);
stand = STAND_UNDERWATER;
return animation.setAnim(ANIM_TO_UNDERWATER);
}
@@ -2039,17 +2037,24 @@ struct Lara : Character {
return stand;
}
if (getRoom().flags.water) {
wpnHide();
if (stand != STAND_UNDERWATER && stand != STAND_ONWATER && (state != STATE_FALL && state != STATE_REACH && state != STATE_SWAN_DIVE && state != STATE_FAST_DIVE))
animation.setAnim(ANIM_FALL_FORTH);
stopScreaming();
return STAND_UNDERWATER;
}
TR::Level::FloorInfo info;
getFloorInfo(getRoomIndex(), pos, info);
if (getRoom().flags.water) {
if (stand == STAND_UNDERWATER || stand == STAND_ONWATER)
return stand;
wpnHide();
if (stand == STAND_AIR) {
//if (stand != STAND_UNDERWATER && stand != STAND_ONWATER && (state != STATE_FALL && state != STATE_REACH && state != STATE_SWAN_DIVE && state != STATE_FAST_DIVE))
// animation.setAnim(ANIM_FALL_FORTH);
stopScreaming();
return STAND_UNDERWATER;
} else {
pos.y = info.roomCeiling;
return STAND_ONWATER;
}
}
if ((stand == STAND_SLIDE || stand == STAND_GROUND) && (state != STATE_FORWARD_JUMP && state != STATE_BACK_JUMP)) {
if (pos.y + 8 >= info.floor && (abs(info.slantX) > 2 || abs(info.slantZ) > 2)) {
pos.y = info.floor;
@@ -2081,6 +2086,8 @@ struct Lara : Character {
}
}
}
if (stand == STAND_UNDERWATER || stand == STAND_ONWATER)
animation.setAnim(ANIM_STAND);
return STAND_GROUND;
}
@@ -2516,6 +2523,9 @@ struct Lara : Character {
//reset(44, vec3(62976, 1536, 23040), 0);
reset(44, vec3(62976, 1536, 23040), 0);
break;
case TR::LVL_TR3_TEMPLE :
reset(204, vec3(40562, 3584, 58694), 0);
break;
default : game->playSound(TR::SND_NO, pos, Sound::PAN);
}
}
@@ -2597,9 +2607,23 @@ struct Lara : Character {
usedKey = TR::Entity::LARA;
}
void updateFlash() {
for (int i = 0; i < 2; i++) {
if (arms[i].shotTimer < MUZZLE_FLASH_TIME) {
arms[i].shotTimer += Core::deltaTime;
float intensity = clamp((0.1f - arms[i].shotTimer) * 20.0f, EPS, 1.0f);
Core::lightColor[1 + i] = FLASH_LIGHT_COLOR * vec4(intensity, intensity, intensity, 1.0f / sqrtf(intensity));
Core::lightPos[1 + i] = animation.getJoints(getMatrix(), i == 0 ? 10 : 13, false).pos;
} else {
Core::lightColor[1 + i] = vec4(0, 0, 0, 1);
}
}
}
virtual void updateAnimation(bool commands) {
Controller::updateAnimation(commands);
updateWeapon();
updateFlash();
if (stand == STAND_UNDERWATER)
specular = 0.0f;
else

View File

@@ -1668,9 +1668,10 @@ struct Level : IGame {
// Debug::Draw::box(bbox.min, bbox.max, vec4(1, 0, 1, 1));
// Core::setBlending(bmAlpha);
// Core::validateRenderState();
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
// Debug::Level::lights(level, lara->getRoomIndex(), lara);
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
// Debug::Level::sectors(this, lara->getRoomIndex(), (int)lara->pos.y);
// Core::setDepthTest(false);
// Debug::Level::portals(level);
// Core::setDepthTest(true);

View File

@@ -22,6 +22,7 @@ struct MeshRange {
glEnableVertexAttribArray(aTexCoord);
glEnableVertexAttribArray(aParam);
glEnableVertexAttribArray(aColor);
glEnableVertexAttribArray(aLight);
Vertex *v = (Vertex*)NULL + vStart;
glVertexAttribPointer(aCoord, 4, GL_SHORT, false, sizeof(Vertex), &v->coord);
@@ -29,6 +30,7 @@ struct MeshRange {
glVertexAttribPointer(aTexCoord, 4, GL_SHORT, true, sizeof(Vertex), &v->texCoord);
glVertexAttribPointer(aParam, 4, GL_UNSIGNED_BYTE, false, sizeof(Vertex), &v->param);
glVertexAttribPointer(aColor, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), &v->color);
glVertexAttribPointer(aLight, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), &v->light);
}
void bind(GLuint *VAO) const {
@@ -316,7 +318,7 @@ struct MeshBuilder {
TR::Room::Data::Vertex &v = d.vertices[f.vertex];
TR::SpriteTexture &sprite = level.spriteTextures[f.texture];
addSprite(indices, vertices, iCount, vCount, vStartRoom, v.vertex.x, v.vertex.y, v.vertex.z, sprite, intensity(v.lighting));
addSprite(indices, vertices, iCount, vCount, vStartRoom, v.vertex.x, v.vertex.y, v.vertex.z, sprite, v.color, v.color);
}
range.sprites.iCount = iCount - range.sprites.iStart;
}
@@ -361,7 +363,7 @@ struct MeshBuilder {
range.iStart = iCount;
for (int j = 0; j < level.spriteSequences[i].sCount; j++) {
TR::SpriteTexture &sprite = level.spriteTextures[level.spriteSequences[i].sStart + j];
addSprite(indices, vertices, iCount, vCount, vStartSprite, 0, 0, 0, sprite, 255);
addSprite(indices, vertices, iCount, vCount, vStartSprite, 0, 0, 0, sprite, TR::Color32(255, 255, 255, 255), TR::Color32(255, 255, 255, 255));
}
range.iCount = iCount - range.iStart;
}
@@ -380,6 +382,7 @@ struct MeshBuilder {
v0.texCoord = { whiteTile.texCoord[0].x, whiteTile.texCoord[0].y, 32767, 32767 };
v0.param = { 0, 0, 0, 0 };
v0.color = { 0, 0, 0, 0 };
v0.light = { 255, 255, 255, 255 };
if (i == 8) {
v0.coord = { 0, 0, 0, 0 };
@@ -399,6 +402,7 @@ struct MeshBuilder {
v1 = v0;
v1.coord = { c1, 0, s1, 0 };
v1.color = { 255, 255, 255, 0 };
v1.light = { 255, 255, 255, 255 };
int idx = iCount + i * 3 * 3;
int j = ((i + 1) % 8) * 2;
@@ -432,6 +436,7 @@ struct MeshBuilder {
Vertex &v = vertices[vCount + i];
v.normal = { 0, 0, 0, 0 };
v.color = { 255, 255, 255, 255 };
v.light = { 255, 255, 255, 255 };
v.texCoord = { whiteTile.texCoord[0].x, whiteTile.texCoord[0].y, 32767, 32767 };
v.param = { 0, 0, 0, 0 };
}
@@ -452,6 +457,7 @@ struct MeshBuilder {
v.coord = { short(pos.x), short(pos.y), 0, 0 };
v.normal = { 0, 0, 0, 0 };
v.color = { 255, 255, 255, 255 };
v.light = { 255, 255, 255, 255 };
v.texCoord = { whiteTile.texCoord[0].x, whiteTile.texCoord[0].y, 32767, 32767 };
v.param = { 0, 0, 0, 0 };
@@ -575,6 +581,7 @@ struct MeshBuilder {
}
void roomRemoveWaterSurfaces(TR::Room &room, int &iCount, int &vCount) {
room.waterLevel = -1;
// remove animated water polygons from room geometry
for (int i = 0; i < room.data.rCount; i++) {
TR::Rectangle &f = room.data.rectangles[i];
@@ -601,6 +608,7 @@ struct MeshBuilder {
if (isWaterSurface(yt, s.roomAbove, room.flags.water) ||
isWaterSurface(yb, s.roomBelow, room.flags.water)) {
f.vertices[0] = 0xFFFF; // mark as unused
room.waterLevel = a.y;
iCount -= 6;
vCount -= 4;
}
@@ -630,6 +638,7 @@ struct MeshBuilder {
if (isWaterSurface(yt, s.roomAbove, room.flags.water) ||
isWaterSurface(yb, s.roomBelow, room.flags.water)) {
f.vertices[0] = 0xFFFF; // mark as unused
room.waterLevel = a.y;
iCount -= 3;
vCount -= 3;
}
@@ -664,8 +673,9 @@ 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, 255 };
TR::Color32 c = v.color;
vertices[vCount].color = { c.b, c.g, c.r, intensity(v.lighting) };
vertices[vCount].light = { c.r, c.g, c.b, 255 };
vCount++;
}
}
@@ -691,8 +701,9 @@ 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, 255 };
TR::Color32 c = v.color;
vertices[vCount].color = { c.b, c.g, c.r, intensity(v.lighting) };
vertices[vCount].light = { c.r, c.g, c.b, 255 };
vCount++;
}
}
@@ -700,7 +711,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, const TR::Color32 &color) {
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 &light) {
TR::Color24 COLOR_WHITE = { 255, 255, 255 };
bool isOpaque = true;
@@ -715,9 +726,6 @@ 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,
@@ -730,7 +738,8 @@ struct MeshBuilder {
vertices[vCount].coord = transform(v.coord, joint, x, y, z, dir);
vertices[vCount].normal = rotate(v.normal, dir);
vertices[vCount].color = { c.r, c.g, c.b, intensity(v.coord.w) };
vertices[vCount].color = { c.r, c.g, c.b, 255 };
vertices[vCount].light = { light.r, light.g, light.b, 255 };
vCount++;
}
@@ -755,7 +764,8 @@ struct MeshBuilder {
vertices[vCount].coord = transform(v.coord, joint, x, y, z, dir);
vertices[vCount].normal = rotate(v.normal, dir);
vertices[vCount].color = { c.r, c.g, c.b, intensity(v.coord.w) };
vertices[vCount].color = { c.r, c.g, c.b, 255 };
vertices[vCount].light = { light.r, light.g, light.b, 255 };
vCount++;
}
@@ -905,7 +915,7 @@ struct MeshBuilder {
}
}
void addSprite(Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 x, int16 y, int16 z, const TR::SpriteTexture &sprite, uint8 intensity, bool expand = false) {
void addSprite(Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 x, int16 y, int16 z, const TR::SpriteTexture &sprite, const TR::Color32 &tColor, const TR::Color32 &bColor, bool expand = false) {
addQuad(indices, iCount, vCount, vStart, NULL, NULL);
Vertex *quad = &vertices[vCount];
@@ -928,7 +938,9 @@ struct MeshBuilder {
quad[3].coord = { x0, y1, z, 0 };
quad[0].normal = quad[1].normal = quad[2].normal = quad[3].normal = { 0, 0, 0, 0 };
quad[0].color = quad[1].color = quad[2].color = quad[3].color = { 255, 255, 255, intensity };
quad[0].color = quad[1].color = { tColor.r, tColor.g, tColor.b, tColor.a };
quad[2].color = quad[3].color = { bColor.r, bColor.g, bColor.b, bColor.a };
quad[0].light = quad[1].light = quad[2].light = quad[3].light = { 255, 255, 255, 255 };
quad[0].param = quad[1].param = quad[2].param = quad[3].param = { 0, 0, 0, 0 };
quad[0].texCoord = { sprite.texCoord[0].x, sprite.texCoord[0].y, sprite.l, sprite.t };

View File

@@ -8,7 +8,8 @@
E( aNormal ) \
E( aTexCoord ) \
E( aParam ) \
E( aColor )
E( aColor ) \
E( aLight )
#define SHADER_SAMPLERS(E) \
E( sDiffuse ) \

View File

@@ -36,6 +36,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
#ifdef OPT_SHADOW
varying vec3 vAmbient;
varying vec4 vLightMap;
#endif
#endif
@@ -78,6 +79,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
#ifndef PASS_SHADOW
attribute vec4 aColor;
attribute vec4 aLight;
#endif
vec3 mulQuat(vec4 q, vec3 v) {
@@ -140,7 +142,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
void _diffuse() {
#ifndef PASS_SHADOW
vDiffuse = vec4(aColor.xyz * (uMaterial.x * 2.0), uMaterial.w);
vDiffuse = vec4(aColor.xyz * (uMaterial.x * 1.8), uMaterial.w);
#ifdef UNDERWATER
vDiffuse.xyz *= UNDERWATER_COLOR;
@@ -171,7 +173,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
lum.x = dot(vNormal.xyz, normalize(lv0));
att.x = dot(lv0, lv0);
#else
lum.x = aColor.w;
lum.x = 1.0;
att.x = 0.0;
#ifdef TYPE_SPRITE
@@ -197,27 +199,28 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
ambient = vec3(uMaterial.y);
#endif
#else
ambient = vec3(min(uMaterial.y, light.x));
ambient = min(uMaterial.yyy, aLight.xyz);
#endif
#ifdef OPT_SHADOW
vAmbient = ambient;
vLight = light;
vAmbient = ambient;
vLight = light;
vLightMap = aLight * light.x;
#else
vLight.w = 0.0;
vLight.xyz = uLightColor[1].xyz * light.y + uLightColor[2].xyz * light.z + uLightColor[3].xyz * light.w;
vLight.w = 0.0;
#ifdef TYPE_ENTITY
vLight.xyz += ambient + uLightColor[0].xyz * light.x;
#else
vLight.xyz += light.x;
vLight.xyz += aLight.xyz * light.x;
#endif
#endif
#endif
#ifdef PASS_AMBIENT
vLight = aColor.wwww;
vLight = vec4(aLight.xyz, 1.0);
#endif
#endif
}
@@ -426,7 +429,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
#if !defined(TYPE_FLASH) && !defined(TYPE_MIRROR)
#ifdef PASS_AMBIENT
color.xyz *= vLight.x;
color.xyz *= vLight.xyz;
#endif
#ifdef PASS_COMPOSE
@@ -450,12 +453,13 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
#endif
#ifdef TYPE_ROOM
light += mix(vAmbient.x, vLight.x, rShadow);
light += mix(vAmbient.xyz, vLightMap.xyz, rShadow);
#endif
#ifdef TYPE_SPRITE
light += vLight.x;
light += vLightMap.xyz;
#endif
#else
vec3 light = vLight.xyz;
#endif

View File

@@ -249,24 +249,32 @@ struct Texture {
stream.read(width);
stream.read(height);
stream.seek(offset - stream.pos);
int dw = Core::support.texNPOT ? width : nextPow2(width);
int dh = Core::support.texNPOT ? height : nextPow2(height);
Color24 *data24 = new Color24[width * height];
Color32 *data32 = new Color32[width * height];
Color32 *data32 = new Color32[dw * dh];
stream.raw(data24, width * height * sizeof(Color24));
Color32 *dst = data32;
for (int y = 0; y < height; y++) {
for (int y = 0; y < dh; 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;
for (int x = 0; x < dw; x++) {
if (x < width && y < height) {
dst->r = src->b;
dst->g = src->g;
dst->b = src->r;
src++;
} else
dst->r = dst->g = dst->b = 0;
dst->a = 255;
dst++;
src++;
}
}
Texture *tex = new Texture(width, height, Texture::RGBA, false, data32);
Texture *tex = new Texture(dw, dh, Texture::RGBA, false, data32);
delete[] data24;
delete[] data32;

View File

@@ -254,12 +254,21 @@ namespace UI {
Core::setDepthTest(true);
}
void textOut(const vec2 &pos, const char *text, Align align = aLeft, float width = 0) {
enum ShadeType {
SHADE_NONE = 0,
SHADE_ORANGE = 1,
SHADE_GRAY = 2,
};
void textOut(const vec2 &pos, const char *text, Align align = aLeft, float width = 0, ShadeType shade = SHADE_ORANGE, bool isShadow = false) {
if (!text) return;
TR::Level *level = game->getLevel();
MeshBuilder *mesh = game->getMesh();
if (shade && !isShadow && ((level->version & TR::VER_TR3)))
textOut(pos + vec2(1, 1), text, align, width, shade, true);
MeshBuilder *mesh = game->getMesh();
int seq = level->extra.glyphs;
int x = int(pos.x);
@@ -291,14 +300,33 @@ namespace UI {
flush();
TR::SpriteTexture &sprite = level->spriteTextures[level->spriteSequences[seq].sStart + frame];
mesh->addSprite(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, 0, x, y, 0, sprite, 255, true);
TR::Color32 tColor, bColor;
if (isShadow) {
tColor = bColor = TR::Color32(0, 0, 0, 255);
} else {
tColor = bColor = TR::Color32(255, 255, 255, 255);
if (shade && ((level->version & TR::VER_TR3))) {
if (shade == SHADE_ORANGE) {
tColor = TR::Color32(255, 190, 90, 255);
bColor = TR::Color32(140, 50, 10, 255);
}
if (shade == SHADE_GRAY) {
tColor = TR::Color32(255, 255, 255, 255);
bColor = TR::Color32(128, 128, 128, 255);
}
}
}
mesh->addSprite(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, 0, x, y, 0, sprite, tColor, bColor, true);
x += char_width[frame] + 1;
}
}
void textOut(const vec2 &pos, StringID str, Align align = aLeft, float width = 0) {
textOut(pos, STR[str], align, width);
void textOut(const vec2 &pos, StringID str, Align align = aLeft, float width = 0, ShadeType shade = SHADE_ORANGE) {
textOut(pos, STR[str], align, width, shade);
}
void specOut(const vec2 &pos, char specChar) {
@@ -311,7 +339,7 @@ namespace UI {
flush();
TR::SpriteTexture &sprite = level->spriteTextures[level->spriteSequences[seq].sStart + specChar];
mesh->addSprite(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, 0, int(pos.x), int(pos.y), 0, sprite, 255, true);
mesh->addSprite(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, 0, int(pos.x), int(pos.y), 0, sprite, TR::Color32(255, 255, 255, 255), TR::Color32(255, 255, 255, 255), true);
}
#undef MAX_CHARS
@@ -402,10 +430,10 @@ namespace UI {
void renderHelp() {
if (showHelp)
textOut(vec2(0, 64), STR_HELP_TEXT, aRight, width - 32);
textOut(vec2(0, 64), STR_HELP_TEXT, aRight, width - 32, UI::SHADE_GRAY);
else
if (helpTipTime > 0.0f)
textOut(vec2(0, 480 - 32), STR_HELP_PRESS, aCenter, width);
textOut(vec2(0, 480 - 32), STR_HELP_PRESS, aCenter, width, UI::SHADE_ORANGE);
}
};