1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-15 01:24:35 +02:00

#22 fix pickup offsets, fix qualopec scion pickup; #22 fix bats falling after death, fix qualopec mummy hit points for blood sprites, fix Lara blocking with enemies; #23 add stereo mode support for 3D displays (SBS)

This commit is contained in:
XProger
2017-10-23 01:28:14 +03:00
parent 91a0c7487d
commit b6ae425d3d
15 changed files with 159 additions and 78 deletions

View File

@@ -691,7 +691,7 @@ struct WaterCache {
Core::invalidateTarget(false, true);
Core::setTarget(NULL);
}
Core::copyTarget(refract, 0, 0, 0, 0, w, h); // copy framebuffer into refraction texture
Core::copyTarget(refract, 0, 0, int(Core::viewportDef.x), int(Core::viewportDef.y), w, h); // copy framebuffer into refraction texture
}
void simulate() {

View File

@@ -39,10 +39,7 @@ struct Camera : ICamera {
Controller* viewTarget;
float speed;
bool firstPerson;
bool isVR;
Camera(IGame *game, Character *owner) : ICamera(), game(game), level(game->getLevel()), owner(owner), frustum(new Frustum()), timer(-1.0f), viewIndex(-1), viewIndexLast(-1), viewTarget(NULL), isVR(false) {
Camera(IGame *game, Character *owner) : ICamera(), game(game), level(game->getLevel()), owner(owner), frustum(new Frustum()), timer(-1.0f), viewIndex(-1), viewIndexLast(-1), viewTarget(NULL) {
changeView(false);
if (owner->getEntity().type != TR::Entity::LARA && level->cameraFrames) {
state = STATE_CUTSCENE;
@@ -323,10 +320,12 @@ struct Camera : ICamera {
}
mViewInv = mat4(pos, target, vec3(0, -1, 0));
if (isVR) {
/*
if (Core::settings.detail.VR) {
mat4 head = Input::head.getMatrix();
mViewInv = mViewInv * head;
}
*/
updateListener();
}
@@ -347,8 +346,8 @@ struct Camera : ICamera {
if (shake > 0.0f)
Core::mView.translate(vec3(0.0f, sinf(shake * PI * 7) * shake * 48.0f, 0.0f));
if (isVR)
Core::mView.translate(Core::mViewInv.right.xyz * (-Core::eye * 32.0f));
if (Core::settings.detail.stereo)
Core::mView.translate(Core::mViewInv.right.xyz * (-Core::eye * (firstPerson ? 8.0f : 32.0f) ));
Core::mProj = getProjMatrix();

View File

@@ -21,6 +21,7 @@ struct ICamera {
vec4 *reflectPlane;
vec3 pos;
float shake;
bool firstPerson;
ICamera() : reflectPlane(NULL), pos(0.0f), shake(0.0f) {}

View File

@@ -186,14 +186,17 @@ namespace Core {
struct Settings {
enum Quality : uint8 { LOW, MEDIUM, HIGH };
union {
struct {
Quality filter;
Quality lighting;
Quality shadows;
Quality water;
struct {
union {
struct {
Quality filter;
Quality lighting;
Quality shadows;
Quality water;
};
Quality quality[4];
};
Quality quality[4];
bool stereo;
void setFilter(Quality value) {
if (value > MEDIUM && !(support.maxAniso > 1))
@@ -448,7 +451,7 @@ namespace Core {
mat4 mView, mProj, mViewProj, mViewInv, mLightProj;
Basis basis;
vec3 viewPos;
vec3 lightPos[MAX_LIGHTS];
vec4 lightPos[MAX_LIGHTS];
vec4 lightColor[MAX_LIGHTS];
vec4 params;
vec4 contacts[MAX_CONTACTS];
@@ -688,6 +691,7 @@ namespace Core {
settings.detail.setLighting (Core::Settings::HIGH);
settings.detail.setShadows (Core::Settings::HIGH);
settings.detail.setWater (Core::Settings::HIGH);
settings.detail.stereo = false;
settings.audio.music = 0.7f;
settings.audio.sound = 0.7f;

View File

@@ -537,7 +537,7 @@ namespace Debug {
TR::Entity &t = level.entities[j];
if (j == i || ((!t.isEnemy() || !t.flags.active) && t.type != TR::Entity::LARA)) continue;
Controller *enemy = (Controller*)t.controller;
if (!controller->getBoundingBox().intersect(enemy->getBoundingBox()))
if (!enemy || !controller->getBoundingBox().intersect(enemy->getBoundingBox()))
continue;
bboxIntersect = true;
mask |= controller->collide(enemy);

View File

@@ -850,6 +850,17 @@ struct Bat : Enemy {
lift(waypoint.y - pos.y, BAT_LIFT_SPEED);
Enemy::updatePosition();
}
virtual void deactivate(bool removeFromList = false) {
if (health <= 0.0f) {
TR::Level::FloorInfo info;
level->getFloorInfo(getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), info);
if (info.floor > pos.y)
return;
pos.y = float(info.floor);
}
Enemy::deactivate(removeFromList);
}
};

View File

@@ -619,7 +619,7 @@ namespace TR {
};
TR::Vertex center;
uint16 radius;
int16 radius;
union {
struct {
uint16 transparent:1, reserved:15;

View File

@@ -466,10 +466,10 @@ struct Inventory {
}
if (item->type == TR::Entity::INV_DETAIL) {
int count = 5;
int count = 6;
if (key == cUp ) { slot = (slot - 1 + count) % count; };
if (key == cDown ) { slot = (slot + 1) % count; };
if (slot < count - 1) {
if (slot < count - 2) {
Core::Settings::Quality q = settings.detail.quality[slot];
if (key == cLeft && q > Core::Settings::LOW ) { q = Core::Settings::Quality(q - 1); }
if (key == cRight && q < Core::Settings::HIGH ) { q = Core::Settings::Quality(q + 1); }
@@ -485,7 +485,10 @@ struct Inventory {
}
}
if (slot == count -1 && key == cAction) {
if (slot == count - 2 && (key == cLeft || key == cRight)) // stereo
settings.detail.stereo = !settings.detail.stereo;
if (slot == count - 1 && key == cAction) { // apply
game->applySettings(settings);
chosen = false;
}
@@ -734,10 +737,13 @@ struct Inventory {
void renderPassport(Item *item) {
if (item->anim->dir != 0.0f) return; // check for "Load Game" page
float y = 120.0f;
float eye = UI::width * Core::eye * 0.02f;
float h = 20.0f;
float w = 320.0f;
float x = (UI::width - w) * 0.5f - eye;
float y = 120.0f;
StringID str = STR_LOAD_GAME;
if (game->getLevel()->id == TR::TITLE) {
@@ -757,19 +763,19 @@ struct Inventory {
if (item->value != 0) return;
// background
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - w - 16.0f) * 0.5f, y - 16.0f), vec2(w + 16.0f, h * 16.0f), 0.0f, 0, 0xC0000000);
UI::renderBar(UI::BAR_OPTION, vec2(x - 8.0f, y - 16.0f), vec2(w + 16.0f, h * 16.0f), 0.0f, 0, 0xC0000000);
// title
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - w) * 0.5f, y - h + 6), vec2(w, h - 6), 1.0f, 0x802288FF, 0, 0, 0);
UI::textOut(vec2(0, y), STR_SELECT_LEVEL, UI::aCenter, UI::width);
UI::renderBar(UI::BAR_OPTION, vec2(x, y - h + 6), vec2(w, h - 6), 1.0f, 0x802288FF, 0, 0, 0);
UI::textOut(vec2(x, y), STR_SELECT_LEVEL, UI::aCenter, w);
y += h * 2;
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - w) * 0.5f, y + slot * h + 6 - h), vec2(w, h - 6), 1.0f, 0xFFD8377C, 0);
UI::renderBar(UI::BAR_OPTION, vec2(x, y + slot * h + 6 - h), vec2(w, h - 6), 1.0f, 0xFFD8377C, 0);
for (int i = 0; i < passportSlotCount; i++)
if (passportSlots[i] == TR::LEVEL_MAX)
UI::textOut(vec2(0, y + i * h), STR_AUTOSAVE, UI::aCenter, UI::width);
UI::textOut(vec2(x, y + i * h), STR_AUTOSAVE, UI::aCenter, w);
else
UI::textOut(vec2(0, y + i * h), TR::LEVEL_INFO[passportSlots[i]].title, UI::aCenter, UI::width);
UI::textOut(vec2(x, y + i * h), TR::LEVEL_INFO[passportSlots[i]].title, UI::aCenter, w);
}
float printBool(float x, float y, float w, StringID oStr, bool active, bool value) {
@@ -812,25 +818,27 @@ struct Inventory {
float w = 320.0f;
float h = 20.0f;
float x = (UI::width - w) * 0.5f;
float y = 192.0f;
float eye = UI::width * Core::eye * 0.02f;
float x = (UI::width - w) * 0.5f - eye;
float y = 192.0f - h;
// background
UI::renderBar(UI::BAR_OPTION, vec2(x, y - 16.0f), vec2(w, h * 8.0f + 8.0f), 0.0f, 0, 0xC0000000);
UI::renderBar(UI::BAR_OPTION, vec2(x, y - 16.0f), vec2(w, h * 9.0f + 8.0f), 0.0f, 0, 0xC0000000);
// title
UI::renderBar(UI::BAR_OPTION, vec2(x, y - h + 6), vec2(w, h - 6), 1.0f, 0x802288FF, 0, 0, 0);
UI::textOut(vec2(0, y), STR_SELECT_DETAIL, UI::aCenter, UI::width);
UI::textOut(vec2(x, y), STR_SELECT_DETAIL, UI::aCenter, w);
y += h * 2;
x += 8.0f;
w -= 16.0f;
float aw = slot == 4 ? (w - 128.0f) : w;
float aw = slot == 5 ? (w - 128.0f) : w;
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - aw) * 0.5f, y + (slot > 3 ? 5 : slot) * h + 6 - h), vec2(aw, h - 6), 1.0f, 0xFFD8377C, 0);
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - aw) * 0.5f - eye, y + (slot > 4 ? 6 : slot) * h + 6 - h), vec2(aw, h - 6), 1.0f, 0xFFD8377C, 0);
y = printQuality(x, y, w, STR_OPT_DETAIL_FILTER, slot == 0, settings.detail.filter);
y = printQuality(x, y, w, STR_OPT_DETAIL_LIGHTING, slot == 1, settings.detail.lighting);
y = printQuality(x, y, w, STR_OPT_DETAIL_SHADOWS, slot == 2, settings.detail.shadows);
y = printQuality(x, y, w, STR_OPT_DETAIL_WATER, slot == 3, settings.detail.water);
y = printBool(x + 32.0f, y, w - 64.0f - 16.0f, STR_OPT_DETAIL_STEREO, slot == 4, settings.detail.stereo);
y += h;
UI::textOut(vec2(x + 64.0f, y), STR_APPLY, UI::aCenter, w - 128.0f);
}
@@ -839,26 +847,27 @@ struct Inventory {
float w = 320.0f;
float h = 20.0f;
float x = (UI::width - w) * 0.5f;
float eye = UI::width * Core::eye * 0.02f;
float x = (UI::width - w) * 0.5f - eye;
float y = 192.0f;
// background
UI::renderBar(UI::BAR_OPTION, vec2(x, y - 16.0f), vec2(w, h * 5.0f + 8.0f), 0.0f, 0, 0xC0000000);
// title
UI::renderBar(UI::BAR_OPTION, vec2(x, y - h + 6), vec2(w, h - 6), 1.0f, 0x802288FF, 0, 0, 0);
UI::textOut(vec2(0, y), STR_SET_VOLUMES, UI::aCenter, UI::width);
UI::textOut(vec2(x, y), STR_SET_VOLUMES, UI::aCenter, w);
y += h * 2;
x += 8.0f;
w -= 16.0f;
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - w) * 0.5f, y + slot * h + 6 - h), vec2(w, h - 6), 1.0f, 0xFFD8377C, 0);
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - w) * 0.5f - eye, y + slot * h + 6 - h), vec2(w, h - 6), 1.0f, 0xFFD8377C, 0);
float aw = w - 64.0f;
aw -= 4.0f;
y = printBar((UI::width - w) * 0.5f, y, w, 0xFF0080FF, 101, slot == 0, Core::settings.audio.music);
y = printBar((UI::width - w) * 0.5f, y, w, 0xFFFF8000, 102, slot == 1, Core::settings.audio.sound);
y = printBar((UI::width - w) * 0.5f - eye, y, w, 0xFF0080FF, 101, slot == 0, Core::settings.audio.music);
y = printBar((UI::width - w) * 0.5f - eye, y, w, 0xFFFF8000, 102, slot == 1, Core::settings.audio.sound);
y = printBool(x + 32.0f, y, w - 64.0f, STR_REVERBERATION, slot == 2, Core::settings.audio.reverb);
}
@@ -979,7 +988,7 @@ struct Inventory {
Core::mLightProj.identity();
Core::mView.identity();
Core::mView.translate(vec3(0, 0, -1286)); // y = -96 in title
Core::mView.translate(vec3(-Core::eye * 8.0f, 0, -1286)); // y = -96 in title
Core::mView.up *= -1.0f;
Core::mView.dir *= -1.0f;

View File

@@ -865,7 +865,7 @@ struct Lara : Character {
vec3 hit = trace(getRoomIndex(), p, t, room, false);
if (arm->target && checkHit(arm->target, p, hit, hit)) {
TR::Entity::Type type = arm->target->getEntity().type;
((Character*)arm->target)->hit(wpnGetDamage());
((Character*)arm->target)->hit(wpnGetDamage(), this);
hit -= d * 64.0f;
if (type != TR::Entity::SCION_TARGET)
Sprite::add(game, TR::Entity::BLOOD, room, (int)hit.x, (int)hit.y, (int)hit.z, Sprite::FRAME_ANIMATED);
@@ -1274,15 +1274,18 @@ struct Lara : Character {
vec3 v = to - from;
if (box.intersect(m, from, v, t)) {
t *= v.length();
v = v.normal();
Sphere spheres[MAX_SPHERES];
int count;
target->getSpheres(spheres, count);
for (int i = 0; i < count; i++)
if (spheres[i].intersect(from, v, t)) {
point = from + v * t;
for (int i = 0; i < count; i++) {
float st;
if (spheres[i].intersect(from, v, st)) {
point = from + v * max(t, st);
return true;
}
}
}
return false;
}
@@ -1651,7 +1654,15 @@ struct Lara : Character {
if ((state != STATE_STOP && state != STATE_TREAD && state != STATE_PUSH_PULL_READY) || !action || !emptyHands())
return false;
vec3 tmpAngle = controller->angle;
vec3 ctrlAngle = controller->angle;
if (stand == STAND_UNDERWATER)
ctrlAngle.x = -25 * DEG2RAD;
if (!limit->alignAngle)
ctrlAngle.y = angle.y;
controller->angle = ctrlAngle;
mat4 m = controller->getMatrix();
controller->angle = tmpAngle;
float fx = 0.0f;
if (!limit->alignHoriz)
@@ -1661,20 +1672,9 @@ struct Lara : Character {
vec3 deltaAbs = pos - targetPos;
vec3 tmpAngle = controller->angle;
vec3 ctrlAngle = controller->angle;
if (stand == STAND_UNDERWATER)
ctrlAngle.x = -25 * DEG2RAD;
if (!limit->alignAngle)
ctrlAngle.y = angle.y;
controller->angle = ctrlAngle;
vec3 deltaRel = (controller->getMatrix().transpose() * vec4(pos - controller->pos, 0.0f)).xyz; // inverse transform
controller->angle = tmpAngle;
vec3 deltaRel = (m.transpose() * vec4(pos - controller->pos, 0.0f)).xyz; // inverse transform
// set item orientation to hack limits check
if (limit->box.contains(deltaRel)) {
float deltaAngY = shortAngle(angle.y, ctrlAngle.y);
@@ -2760,7 +2760,7 @@ struct Lara : Character {
if (e.isEnemy()) { // enemy collision
if (!collide(controller, false))
continue;
velocity.x = velocity.y = 0.0f;
// velocity.x = velocity.y = 0.0f;
} else { // door collision
p += box.pushOut2D(p);
p = (p.rotateY(-controller->angle.y) + controller->pos) - pos;
@@ -2769,10 +2769,10 @@ struct Lara : Character {
if (e.type == TR::Entity::ENEMY_REX && ((Character*)controller)->health <= 0)
return true;
if (!e.isEnemy())
if (!e.isEnemy() || e.type == TR::Entity::ENEMY_BAT)
return true;
if (canHitAnim()) {
if (canHitAnim()) { // TODO: check enemy type and health here
// get hit dir
if (hitDir == -1) {
if (health > 0)
@@ -3015,7 +3015,12 @@ struct Lara : Character {
}
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
uint32 visMask = visibleMask;
if (Core::pass != Core::passShadow && game->getCamera()->firstPerson) // hide head from first person view
visibleMask &= ~BODY_HEAD;
Controller::render(frustum, mesh, type, caustics);
visibleMask = visMask;
chestOffset = animation.getJoints(getMatrix(), jointChest).pos; // TODO: move to update func
if (braid)

View File

@@ -209,7 +209,7 @@ struct Level : IGame {
atlas->bind(sDiffuse);
Core::whiteTex->bind(sNormal);
Core::whiteTex->bind(sMask);
Core::whiteTex->bind(sReflect);
Core::whiteTex->bind(sReflect);
cube->bind(sEnvironment);
Core::basis.identity();
}
@@ -964,7 +964,7 @@ struct Level : IGame {
}
void update() {
if (isCutscene() && (lara->health > 0.0f && !sndSoundtrack))
if (level.isCutsceneLevel() && (lara->health > 0.0f && !sndSoundtrack))
return;
if (Input::state[cInventory] && level.id != TR::TITLE) {
@@ -1185,8 +1185,6 @@ struct Level : IGame {
virtual void renderView(int roomIndex, bool water) {
PROFILE_MARKER("VIEW");
Core::Pass pass = Core::pass;
if (water && waterCache) {
waterCache->reset();
}
@@ -1203,7 +1201,10 @@ struct Level : IGame {
for (int i = 0; i < roomsCount; i++)
waterCache->setVisible(roomsList[i]);
waterCache->renderReflect();
Core::Pass pass = Core::pass;
waterCache->simulate();
Core::pass = pass;
}
// clear visibility flag for rooms
@@ -1212,24 +1213,24 @@ struct Level : IGame {
level.entities[i].flags.rendered = false;
if (water) {
Core::setTarget(NULL, true); // render to back buffer
Core::setTarget(NULL, !Core::settings.detail.stereo); // render to back buffer
setupBinding();
}
camera->setup(Core::pass == Core::passCompose);
Core::pass = pass;
renderRooms(roomsList, roomsCount);
if (Core::pass != Core::passAmbient)
renderEntities();
if (water && waterCache && waterCache->visible) {
Core::Pass pass = Core::pass;
waterCache->renderMask();
waterCache->getRefract();
setMainLight(lara);
waterCache->render();
Core::pass = pass;
}
}
@@ -1536,13 +1537,43 @@ struct Level : IGame {
if (shadow) shadow->bind(sShadow);
Core::pass = Core::passCompose;
setup();
renderView(camera->getRoomIndex(), true);
if (Core::settings.detail.stereo) {
Core::setTarget(NULL, true);
Core::validateRenderState();
}
if (Core::settings.detail.stereo) {
Core::viewportDef = vec4(0.0f, 0.0f, float(Core::width) * 0.5f, float(Core::height));
Core::eye = -1.0f;
setup();
renderView(camera->getRoomIndex(), true);
Core::viewportDef = vec4(float(Core::width) * 0.5f, 0.0f, float(Core::width) * 0.5f, float(Core::height));
Core::eye = 1.0f;
setup();
renderView(camera->getRoomIndex(), true);
Core::viewportDef = vec4(0.0f, 0.0f, float(Core::width), float(Core::height));
Core::eye = 0.0f;
} else {
setup();
renderView(camera->getRoomIndex(), true);
}
}
void renderInventory() {
Core::setTarget(NULL, true);
inventory.render();
if (Core::settings.detail.stereo) {
Core::setViewport(0, 0, Core::width / 2, Core::height);
Core::eye = -1.0f;
inventory.render();
Core::setViewport(Core::width / 2, 0, Core::width / 2, Core::height);
Core::eye = 1.0f;
inventory.render();
Core::setViewport(0, 0, Core::width, Core::height);
Core::eye = 0.0f;
} else
inventory.render();
}
void renderUI() {
@@ -1562,18 +1593,20 @@ struct Level : IGame {
if (oxygen <= 0.2f) oxygen = 0.0f;
}
float eye = inventory.active ? 0.0f : UI::width * Core::eye * 0.02f;
if (inventory.showHealthBar() || (!inventory.active && (!lara->emptyHands() || lara->damageTime > 0.0f || health <= 0.2f))) {
UI::renderBar(UI::BAR_HEALTH, vec2(UI::width - 32 - size.x, 32), size, health);
UI::renderBar(UI::BAR_HEALTH, vec2(UI::width - 32 - size.x - eye, 32), size, health);
if (!inventory.active && !lara->emptyHands()) { // ammo
int index = inventory.contains(lara->getCurrentWeaponInv());
if (index > -1)
inventory.renderItemCount(inventory.items[index], vec2(UI::width - 32 - size.x, 64), size.x);
inventory.renderItemCount(inventory.items[index], vec2(UI::width - 32 - size.x - eye, 64), size.x);
}
}
if (!lara->dozy && (lara->stand == Lara::STAND_ONWATER || lara->stand == Character::STAND_UNDERWATER))
UI::renderBar(UI::BAR_OXYGEN, vec2(32, 32), size, oxygen);
UI::renderBar(UI::BAR_OXYGEN, vec2(32 - eye, 32), size, oxygen);
}
inventory.renderUI();
@@ -1599,7 +1632,10 @@ struct Level : IGame {
if (copyBg) {
Core::defaultTarget = inventory.background[0];
bool stereo = Core::settings.detail.stereo;
Core::settings.detail.stereo = false;
renderGame();
Core::settings.detail.stereo = stereo;
Core::defaultTarget = NULL;
inventory.prepareBackground();
@@ -1611,7 +1647,17 @@ struct Level : IGame {
if (title)
renderInventory();
renderUI();
if (Core::settings.detail.stereo) {
Core::setViewport(0, 0, Core::width / 2, Core::height);
Core::eye = -1.0f;
renderUI();
Core::setViewport(Core::width / 2, 0, Core::width / 2, Core::height);
Core::eye = 1.0f;
renderUI();
Core::setViewport(0, 0, Core::width, Core::height);
Core::eye = 0.0f;
} else
renderUI();
}
};

View File

@@ -159,8 +159,11 @@ struct Shader {
void init() {
bind();
for (int st = 0; st < sMAX; st++)
glUniform1iv(glGetUniformLocation(ID, (GLchar*)SamplerName[st]), 1, &st);
for (int st = 0; st < sMAX; st++) {
GLint idx = glGetUniformLocation(ID, (GLchar*)SamplerName[st]);
if (idx != -1)
glUniform1iv(idx, 1, &st);
}
for (int ut = 0; ut < uMAX; ut++)
uID[ut] = glGetUniformLocation(ID, (GLchar*)UniformName[ut]);

View File

@@ -19,7 +19,7 @@ uniform mat4 uLightProj;
uniform mat4 uViewProj;
uniform vec3 uViewPos;
uniform vec4 uParam; // x - time, y - water height, z - clip plane sign, w - clip plane height
uniform vec3 uLightPos[MAX_LIGHTS];
uniform vec4 uLightPos[MAX_LIGHTS];
uniform vec4 uLightColor[MAX_LIGHTS]; // xyz - color, w - radius * intensity
uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha

View File

@@ -14,7 +14,7 @@ varying vec3 vLightVec;
uniform vec3 uViewPos;
uniform mat4 uViewProj;
uniform vec3 uLightPos;
uniform vec4 uLightPos;
uniform vec3 uPosScale[2];
uniform vec4 uTexParam;
@@ -71,7 +71,7 @@ uniform sampler2D sNormal;
#endif
#endif
vViewVec = uViewPos - vCoord.xyz;
vLightVec = uLightPos - vCoord.xyz;
vLightVec = uLightPos.xyz - vCoord.xyz;
}
#else
uniform sampler2D sDiffuse;

View File

@@ -43,6 +43,7 @@ enum StringID {
, STR_OPT_DETAIL_LIGHTING
, STR_OPT_DETAIL_SHADOWS
, STR_OPT_DETAIL_WATER
, STR_OPT_DETAIL_STEREO
// sound options
, STR_SET_VOLUMES
, STR_REVERBERATION
@@ -132,6 +133,7 @@ const char *STR[STR_MAX] = {
, "Lighting"
, "Shadows"
, "Water"
, "Stereo"
// sound options
, "Set Volumes"
, "Reverberation"

View File

@@ -283,6 +283,7 @@ struct vec4 {
vec4() {}
vec4(float s) : x(s), y(s), z(s), w(s) {}
vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
vec4(const vec3 &xyz) : x(xyz.x), y(xyz.y), z(xyz.z), w(0) {}
vec4(const vec3 &xyz, float w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
vec4(const vec2 &xy, const vec2 &zw) : x(xy.x), y(xy.y), z(zw.x), w(zw.y) {}