From b6ae425d3d643c57794e23233217cdb827da4419 Mon Sep 17 00:00:00 2001 From: XProger Date: Mon, 23 Oct 2017 01:28:14 +0300 Subject: [PATCH] #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) --- src/cache.h | 2 +- src/camera.h | 13 ++++---- src/controller.h | 1 + src/core.h | 20 ++++++----- src/debug.h | 2 +- src/enemy.h | 11 ++++++ src/format.h | 2 +- src/inventory.h | 53 +++++++++++++++++------------ src/lara.h | 43 +++++++++++++----------- src/level.h | 74 +++++++++++++++++++++++++++++++++-------- src/shader.h | 7 ++-- src/shaders/shader.glsl | 2 +- src/shaders/water.glsl | 4 +-- src/ui.h | 2 ++ src/utils.h | 1 + 15 files changed, 159 insertions(+), 78 deletions(-) diff --git a/src/cache.h b/src/cache.h index b83004c..a8bc4a6 100644 --- a/src/cache.h +++ b/src/cache.h @@ -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() { diff --git a/src/camera.h b/src/camera.h index c4cd01f..d97596e 100644 --- a/src/camera.h +++ b/src/camera.h @@ -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(); diff --git a/src/controller.h b/src/controller.h index d0f07c5..8980642 100644 --- a/src/controller.h +++ b/src/controller.h @@ -21,6 +21,7 @@ struct ICamera { vec4 *reflectPlane; vec3 pos; float shake; + bool firstPerson; ICamera() : reflectPlane(NULL), pos(0.0f), shake(0.0f) {} diff --git a/src/core.h b/src/core.h index 3489bfb..c4a8a3d 100644 --- a/src/core.h +++ b/src/core.h @@ -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; diff --git a/src/debug.h b/src/debug.h index a6e6936..eee3800 100644 --- a/src/debug.h +++ b/src/debug.h @@ -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); diff --git a/src/enemy.h b/src/enemy.h index 3811e31..4f2869a 100644 --- a/src/enemy.h +++ b/src/enemy.h @@ -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); + } }; diff --git a/src/format.h b/src/format.h index fb4e0dc..be0e3ac 100644 --- a/src/format.h +++ b/src/format.h @@ -619,7 +619,7 @@ namespace TR { }; TR::Vertex center; - uint16 radius; + int16 radius; union { struct { uint16 transparent:1, reserved:15; diff --git a/src/inventory.h b/src/inventory.h index 2eba64b..b1601ef 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -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; diff --git a/src/lara.h b/src/lara.h index 3d93965..341c717 100644 --- a/src/lara.h +++ b/src/lara.h @@ -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) diff --git a/src/level.h b/src/level.h index 2cbd63e..0b2a192 100644 --- a/src/level.h +++ b/src/level.h @@ -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(); } }; diff --git a/src/shader.h b/src/shader.h index 842ea7b..cd12e38 100644 --- a/src/shader.h +++ b/src/shader.h @@ -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]); diff --git a/src/shaders/shader.glsl b/src/shaders/shader.glsl index 931c075..a224907 100644 --- a/src/shaders/shader.glsl +++ b/src/shaders/shader.glsl @@ -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 diff --git a/src/shaders/water.glsl b/src/shaders/water.glsl index f7a0d6b..2d57ab2 100644 --- a/src/shaders/water.glsl +++ b/src/shaders/water.glsl @@ -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; diff --git a/src/ui.h b/src/ui.h index a0fc80f..9e2023c 100644 --- a/src/ui.h +++ b/src/ui.h @@ -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" diff --git a/src/utils.h b/src/utils.h index 862f407..3a85ef8 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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) {}