1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-17 18:36:43 +02:00

#23 GoogleVR support; minor fixes

This commit is contained in:
XProger
2018-04-06 02:56:10 +03:00
parent d40f451b09
commit e9765b5c4b
19 changed files with 604 additions and 281 deletions

View File

@@ -775,13 +775,10 @@ struct WaterCache {
// render mirror reflection
Core::setTarget(reflect, CLEAR_ALL);
Core::validateRenderState();
Camera *camera = (Camera*)game->getCamera();
game->setupBinding();
mat4 mProj = Core::mProj;
mat4 mView = Core::mView;
mat4 mViewInv = Core::mViewInv;
// merge visible rooms for all items
int roomsList[256];
int roomsCount = 0;
@@ -835,12 +832,8 @@ struct WaterCache {
Core::invalidateTarget(false, true);
game->setClipParams(1.0f, NO_CLIP_PLANE);
Core::mProj = mProj;
Core::mView = mView;
Core::mViewInv = mViewInv;
camera->reflectPlane = NULL;
camera->setup(false);
camera->setup(true);
}
void render() {

View File

@@ -68,9 +68,9 @@ struct Camera : ICamera {
return eye.room;
}
void updateListener() {
void updateListener(const mat4 &matrix) {
Sound::flipped = level->state.flags.flipped;
Sound::listener[cameraIndex].matrix = mViewInv;
Sound::listener[cameraIndex].matrix = matrix;
if (cameraIndex == 0) { // reverb effect only for main player
TR::Room &r = level->rooms[getRoomIndex()];
int h = (r.info.yBottom - r.info.yTop) / 1024;
@@ -148,6 +148,9 @@ struct Camera : ICamera {
fpHead.pos -= joint.rot * vec3(0, 48, -24);
}
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
fpHead.rot = quat(vec3(1, 0, 0), PI);
mViewInv.identity();
mViewInv.setRot(fpHead.rot);
mViewInv.setPos(fpHead.pos);
@@ -155,7 +158,6 @@ struct Camera : ICamera {
eye.pos = mViewInv.getPos();
eye.room = owner->getRoomIndex();
level->getSector(eye.room, fpHead.pos);
return true;
}
@@ -302,8 +304,6 @@ struct Camera : ICamera {
if (eye.pos.y > floor) eye.pos.y = floor;
if (eye.pos.y < ceiling) eye.pos.y = ceiling;
level->getSector(eye.room, eye.pos);
}
virtual void update() {
@@ -350,8 +350,6 @@ struct Camera : ICamera {
mViewInv = mat4(eye.pos, target.pos, vec3(0, -1, 0));
} else
updateFirstPerson();
level->getSector(eye.room, eye.pos);
} else {
Controller *lookAt = NULL;
@@ -371,43 +369,47 @@ struct Camera : ICamera {
owner->lookAt(NULL);
}
vec3 advAngleOld = advAngle;
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) {
advAngle = vec3(0.0f);
} else {
vec3 advAngleOld = advAngle;
if (Input::down[ikMouseL]) {
vec2 delta = Input::mouse.pos - Input::mouse.start.L;
advAngle.x -= delta.y * 0.01f;
advAngle.y += delta.x * 0.01f;
advAngle.y = clamp(advAngle.y, -PI, PI);
Input::mouse.start.L = Input::mouse.pos;
}
// TODO: use player index
if (Input::state[cameraIndex][cLook]) {
float d = 2.0f * Core::deltaTime;
advAngle.x += Input::joy[cameraIndex].L.y * d;
advAngle.y += Input::joy[cameraIndex].L.x * d;
if (Input::state[cameraIndex][cUp]) advAngle.x -= d;
if (Input::state[cameraIndex][cDown]) advAngle.x += d;
if (Input::state[cameraIndex][cLeft]) advAngle.y += d;
if (Input::state[cameraIndex][cRight]) advAngle.y -= d;
}
if (advAngleOld == advAngle) {
if (advTimer > 0.0f) {
advTimer = max(0.0f, advTimer - Core::deltaTime);
if (Input::down[ikMouseL]) {
vec2 delta = Input::mouse.pos - Input::mouse.start.L;
advAngle.x -= delta.y * 0.01f;
advAngle.y += delta.x * 0.01f;
advAngle.y = clamp(advAngle.y, -PI, PI);
Input::mouse.start.L = Input::mouse.pos;
}
} else
advTimer = -1.0f;
if (owner->velocity != 0.0f && advTimer < 0.0f && !Input::down[ikMouseL])
advTimer = -advTimer;
// TODO: use player index
if (Input::state[cameraIndex][cLook]) {
float d = 2.0f * Core::deltaTime;
if (advTimer == 0.0f && advAngle != 0.0f) {
float t = 10.0f * Core::deltaTime;
advAngle.x = lerp(clampAngle(advAngle.x), 0.0f, t);
advAngle.y = lerp(clampAngle(advAngle.y), 0.0f, t);
advAngle.x += Input::joy[cameraIndex].L.y * d;
advAngle.y += Input::joy[cameraIndex].L.x * d;
if (Input::state[cameraIndex][cUp]) advAngle.x -= d;
if (Input::state[cameraIndex][cDown]) advAngle.x += d;
if (Input::state[cameraIndex][cLeft]) advAngle.y += d;
if (Input::state[cameraIndex][cRight]) advAngle.y -= d;
}
if (advAngleOld == advAngle) {
if (advTimer > 0.0f) {
advTimer = max(0.0f, advTimer - Core::deltaTime);
}
} else
advTimer = -1.0f;
if (owner->velocity != 0.0f && advTimer < 0.0f && !Input::down[ikMouseL])
advTimer = -advTimer;
if (advTimer == 0.0f && advAngle != 0.0f) {
float t = 10.0f * Core::deltaTime;
advAngle.x = lerp(clampAngle(advAngle.x), 0.0f, t);
advAngle.y = lerp(clampAngle(advAngle.y), 0.0f, t);
}
}
targetAngle = owner->angle + advAngle;
@@ -466,13 +468,15 @@ struct Camera : ICamera {
mViewInv = mat4(eye.pos, target.pos, vec3(0, -1, 0));
} else
updateFirstPerson();
if (Core::settings.detail.vr) {
mViewInv = mViewInv * Input::hmd.eye[0];
}
}
updateListener();
level->getSector(eye.room, eye.pos);
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
updateListener(mViewInv * Input::hmd.head);
else
updateListener(mViewInv);
smooth = true;
}
@@ -480,30 +484,34 @@ struct Camera : ICamera {
if (calcMatrices) {
Core::mViewInv = mViewInv;
if (Core::settings.detail.vr)
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
Core::mViewInv = Core::mViewInv * Input::hmd.eye[Core::eye == -1.0f ? 0 : 1];
if (shake > 0.0f)
Core::mViewInv.setPos(Core::mViewInv.getPos() + vec3(0.0f, sinf(shake * PI * 7) * shake * 48.0f, 0.0f));
if (Core::settings.detail.stereo == Core::Settings::STEREO_ON)
Core::mViewInv.setPos(Core::mViewInv.getPos() + Core::mViewInv.right().xyz() * (Core::eye * (firstPerson ? 8.0f : 32.0f) ));
if (reflectPlane) {
Core::mViewInv = mat4(*reflectPlane) * Core::mViewInv;
Core::mViewInv.scale(vec3(1.0f, -1.0f, 1.0f));
}
Core::mView = Core::mViewInv.inverseOrtho();
if (shake > 0.0f)
Core::mView.translate(vec3(0.0f, sinf(shake * PI * 7) * shake * 48.0f, 0.0f));
if (Core::settings.detail.stereo == Core::Settings::STEREO_ON)
Core::mView.translate(Core::mViewInv.right().xyz() * (-Core::eye * (firstPerson ? 8.0f : 32.0f) ));
if (Core::settings.detail.vr)
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
Core::mProj = Input::hmd.proj[Core::eye == -1.0f ? 0 : 1];
else
Core::mProj = mat4(fov, aspect, znear, zfar);
}
Core::setViewProj(Core::mView, Core::mProj);
Core::viewPos = Core::mViewInv.getPos();
Core::viewPos = Core::mViewInv.offset().xyz();
// update room for eye (with HMD offset)
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
level->getSector(eye.room, Core::viewPos);
frustum->pos = Core::viewPos;
frustum->calcPlanes(Core::mViewProj);

View File

@@ -49,6 +49,8 @@
#define glProgramBinary glProgramBinaryOES
#define GL_PROGRAM_BINARY_LENGTH GL_PROGRAM_BINARY_LENGTH_OES
extern void osToggleVR(bool enable);
#elif __RPI__
#define MOBILE
#include <GLES2/gl2.h>
@@ -277,7 +279,7 @@ struct KeySet {
namespace Core {
float deltaTime;
int lastTime;
int width, height;
int x, y, width, height;
struct Support {
int maxVectors;
@@ -298,12 +300,12 @@ namespace Core {
#endif
} support;
#define SETTINGS_VERSION 1
#define SETTINGS_VERSION 2
#define SETTINGS_READING 0xFF
struct Settings {
enum Quality { LOW, MEDIUM, HIGH };
enum Stereo { STEREO_OFF, STEREO_ON, STEREO_SPLIT };
enum Stereo { STEREO_OFF, STEREO_ON, STEREO_SPLIT, STEREO_VR };
uint8 version;
@@ -319,7 +321,6 @@ namespace Core {
};
uint8 vsync;
uint8 stereo;
uint8 vr;
void setFilter(Quality value) {
if (value > MEDIUM && !(support.maxAniso > 1))
value = MEDIUM;
@@ -674,7 +675,7 @@ namespace Core {
} reqTarget;
struct Stats {
int dips, tris, frame, fps, fpsTime;
int dips, tris, rt, frame, fps, fpsTime;
#ifdef PROFILE
int tFrame;
#endif
@@ -682,12 +683,12 @@ namespace Core {
Stats() : frame(0), fps(0), fpsTime(0) {}
void start() {
dips = tris = 0;
dips = tris = rt = 0;
}
void stop() {
if (fpsTime < Core::getTime()) {
LOG("FPS: %d DIP: %d TRI: %d\n", fps, dips, tris);
LOG("FPS: %d DIP: %d TRI: %d RT: %d\n", fps, dips, tris, rt);
#ifdef PROFILE
LOG("frame time: %d mcs\n", tFrame / 1000);
#endif
@@ -751,6 +752,7 @@ namespace Core {
}
void init() {
x = y = 0;
#ifdef USE_INFLATE
tinf_init();
#endif
@@ -941,6 +943,10 @@ namespace Core {
support.colorHalf ? "full" : (support.texHalf ? (support.texHalfLinear ? "linear" : "nearest") : "false"));
LOG("\n");
#ifndef _PSP
glEnable(GL_SCISSOR_TEST);
#endif
#ifdef FFP
#ifdef _PSP
Core::width = 480;
@@ -1116,6 +1122,9 @@ namespace Core {
eyeTex[0] = eyeTex[1] = NULL;
memset(&active, 0, sizeof(active));
renderState = 0;
resetTime();
}
@@ -1194,6 +1203,7 @@ namespace Core {
sceGuDrawBufferList(GU_PSM_5650, target->offset, target->width);
*/
#else
Core::stats.rt++;
if (!target) { // may be a null
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
} else {
@@ -1223,6 +1233,7 @@ namespace Core {
sceGuViewport(2048 + int(viewport.x), 2048 + int(viewport.y), int(viewport.z), int(viewport.w));
#else
glViewport(int(viewport.x), int(viewport.y), int(viewport.z), int(viewport.w));
glScissor(int(viewport.x), int(viewport.y), int(viewport.z), int(viewport.w));
#endif
}
renderState &= ~RS_VIEWPORT;
@@ -1468,16 +1479,30 @@ namespace Core {
#endif
}
void beginFrame() {
//memset(&active, 0, sizeof(active));
setViewport(0, 0, Core::width, Core::height);
void reset() {
#ifndef _PSP
if (Core::support.VAO)
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
#endif
memset(&active, 0, sizeof(active));
renderState = 0;
setViewport(Core::x, Core::y, Core::width, Core::height);
viewportDef = viewport;
setCulling(cfFront);
setBlending(bmAlpha);
setDepthTest(true);
setDepthWrite(true);
setColorWrite(true, true, true, true);
validateRenderState();
}
void beginFrame() {
Core::stats.start();
}

View File

@@ -10,6 +10,9 @@
#define MAX_TRIGGER_COMMANDS 32
#define MAX_MESHES 512
// Lara's height in units / height in meters
#define ONE_METER (768.0f / 1.8f)
#define TR1_TYPES_START 0
#define TR2_TYPES_START 1000
#define TR3_TYPES_START 2000

View File

@@ -39,6 +39,11 @@ void loadSettings(Stream *stream, void *userData) {
delete stream;
}
#ifdef ANDROID
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
osToggleVR(true);
#endif
Core::settings.version = SETTINGS_VERSION;
shaderCache = new ShaderCache();
Game::startLevel((Stream*)userData);
@@ -162,22 +167,37 @@ namespace Game {
return true;
}
void render() {
if (Core::settings.version == SETTINGS_READING)
return;
void frameBegin() {
if (Core::settings.version == SETTINGS_READING) return;
Core::reset();
Core::beginFrame();
level->renderPrepare();
}
void frameRender() {
if (Core::settings.version == SETTINGS_READING) return;
PROFILE_MARKER("RENDER");
PROFILE_TIMING(Core::stats.tFrame);
Core::beginFrame();
level->render();
UI::renderTouch();
level->render();
#ifdef _DEBUG
level->renderDebug();
#endif
#endif
}
void frameEnd() {
if (Core::settings.version == SETTINGS_READING) return;
UI::renderTouch();
Core::endFrame();
}
void render() {
frameBegin();
frameRender();
frameEnd();
}
}
#endif

View File

@@ -32,6 +32,7 @@ namespace Input {
} touch[6];
struct HMD {
mat4 head;
mat4 eye[2];
mat4 proj[2];
mat4 controllers[2];
@@ -46,7 +47,10 @@ namespace Input {
}
void reset() {
//
eye[0].identity();
eye[1].identity();
proj[0].identity();
proj[1].identity();
}
} hmd;

View File

@@ -129,7 +129,13 @@ static const OptionItem optDetail[] = {
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_VSYNC, SETTINGS( detail.vsync ), STR_OFF, 0, 1 ),
#endif
#ifndef _PSP
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_STEREO, SETTINGS( detail.stereo ), STR_OFF, 0, 2 ),
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_STEREO, SETTINGS( detail.stereo ), STR_OFF, 0,
#if /*defined(_WIN32) ||*/ defined(ANDROID)
3 /* with VR option */
#else
2 /* without VR support */
#endif
),
#endif
OptionItem( ),
OptionItem( OptionItem::TYPE_BUTTON, STR_APPLY ),
@@ -218,6 +224,8 @@ struct Inventory {
TR::LevelID nextLevel; // toggle result
ControlKey lastKey;
mat4 head;
int slot;
Core::Settings settings;
@@ -423,14 +431,11 @@ struct Inventory {
Core::setBasis(joints, m.mCount);
Core::setBlending(bmNone);
Core::setBlending(bmAlpha);
mesh->transparent = 0;
mesh->renderModel(desc.model);
Core::setBlending(bmAlpha);
mesh->transparent = 1;
mesh->renderModel(desc.model);
Core::setBlending(bmAdd);
Core::setDepthWrite(false);
mesh->transparent = 2;
@@ -675,6 +680,8 @@ struct Inventory {
index = targetIndex = pageItemIndex[page];
head = Input::hmd.head.inverseOrtho();
//if (type == TR::Entity::INV_PASSPORT) // toggle after death
// chooseItem();
}
@@ -1090,6 +1097,9 @@ struct Inventory {
}
void prepareBackground() {
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
return;
#ifdef _PSP
return;
#endif
@@ -1206,9 +1216,7 @@ struct Inventory {
y = options[i].render(x, y, width, slot == i, &stg);
}
void renderItemText(Item *item) {
float eye = UI::width * Core::eye * 0.01f;
void renderItemText(float eye, Item *item) {
if (item->type == TR::Entity::INV_PASSPORT && phaseChoose == 1.0f) {
//
} else
@@ -1257,6 +1265,8 @@ struct Inventory {
if (phaseSelect < 1.0f)
angle = lerpAngle(angle, getAngle(targetIndex, count), hermite(phaseSelect));
Basis basis = Basis(quat(vec3(1, 0, 0), ringTilt), vec3(0));
int itemIndex = 0;
for (int i = 0; i < itemsCount; i++) {
Item *item = items[i];
@@ -1266,7 +1276,6 @@ struct Inventory {
float a = getAngle(itemIndex, count) - angle - collapseAngle;
float ia = item->angle;
float ra = ringTilt;
float rd = radius;
float rh = ringHeight;
@@ -1276,10 +1285,9 @@ struct Inventory {
rd += 296 * phaseChoose;
}
Basis basis = Basis(quat(vec3(1, 0, 0), ra), vec3(0.0f));
basis = basis * Basis(quat(vec3(0, 1, 0), PI + ia - a), vec3(sinf(a), 0, -cosf(a)) * rd - vec3(0, item->desc.page * INVENTORY_HEIGHT - rh, 0));
Basis b = basis * Basis(quat(vec3(0, 1, 0), PI + ia - a), vec3(sinf(a), 0, -cosf(a)) * rd - vec3(0, item->desc.page * INVENTORY_HEIGHT - rh, 0));
item->render(game, basis);
item->render(game, b);
itemIndex++;
}
@@ -1387,23 +1395,32 @@ struct Inventory {
#endif
Index indices[6] = { 0, 1, 2, 0, 2, 3 };
Vertex vertices[4];
vertices[ 0].coord = short4(-32767, 32767, 0, 0);
vertices[ 1].coord = short4( 32767, 32767, 0, 0);
vertices[ 2].coord = short4( 32767, -32767, 0, 0);
vertices[ 3].coord = short4(-32767, -32767, 0, 0);
vertices[ 0].light =
vertices[ 1].light =
vertices[ 2].light =
vertices[ 3].light = ubyte4(255, 255, 255, uint8(phaseRing * 255));
vertices[ 0].texCoord = short4( 0, 32767, 0, 0);
vertices[ 1].texCoord = short4(32767, 32767, 0, 0);
vertices[ 2].texCoord = short4(32767, 0, 0, 0);
vertices[ 3].texCoord = short4( 0, 0, 0, 0);
vertices[0].coord = short4(-32767, 32767, 0, 0);
vertices[1].coord = short4( 32767, 32767, 0, 0);
vertices[2].coord = short4( 32767, -32767, 0, 0);
vertices[3].coord = short4(-32767, -32767, 0, 0);
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) {
vertices[0].light =
vertices[1].light =
vertices[2].light =
vertices[3].light = ubyte4(0, 0, 0, uint8(phaseRing * 255));
} else {
vertices[0].light =
vertices[1].light =
vertices[2].light =
vertices[3].light = ubyte4(255, 255, 255, uint8(phaseRing * 255));
}
vertices[0].texCoord = short4( 0, 32767, 0, 0);
vertices[1].texCoord = short4(32767, 32767, 0, 0);
vertices[2].texCoord = short4(32767, 0, 0, 0);
vertices[3].texCoord = short4( 0, 0, 0, 0);
game->setShader(Core::passFilter, Shader::DEFAULT, false, false);
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
Core::whiteTex->bind(sDiffuse); // black background
else
background[0]->bind(sDiffuse); // blured grayscale image
// blured grayscale image
background[0]->bind(sDiffuse);
Core::setBlending(phaseRing < 1.0f ? bmAlpha : bmNone);
game->getMesh()->renderBuffer(indices, COUNT(indices), vertices, COUNT(vertices));
}
@@ -1414,17 +1431,57 @@ struct Inventory {
Core::setDepthTest(false);
if (background[0]) {
if (background[1])
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) {
if (game->getLevel()->isTitle()) {
if (background[0]) {
renderTitleBG();
}
} else
renderGameBG();
else
renderTitleBG();
} else {
if (background[0]) {
if (background[1])
renderGameBG();
else
renderTitleBG();
}
}
Core::setBlending(bmAlpha);
Core::setDepthTest(true);
}
void setupCamera(float aspect, bool ui = false) {
vec3 pos = vec3(0, 0, -1286);
if (ui) {
pos.x += UI::width * 0.5f;
pos.y += UI::height * 0.5f;
pos.z += 1024.0f;
}
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
pos.z -= 256.0f;
if (Core::settings.detail.stereo == Core::Settings::STEREO_ON)
pos.x += Core::eye * 8.0f;
Core::mViewInv = mat4(pos, pos + vec3(0, 0, 1), vec3(0, -1, 0));
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
Core::mViewInv = Core::mViewInv * head * Input::hmd.eye[Core::eye == -1.0f ? 0 : 1];
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
Core::mProj = Input::hmd.proj[Core::eye == -1.0f ? 0 : 1];
else
Core::mProj = mat4(70.0f, aspect, 32.0f, 2048.0f);
Core::mView = Core::mViewInv.inverseOrtho();
Core::viewPos = Core::mViewInv.getPos();
Core::setViewProj(Core::mView, Core::mProj);
}
void render(float aspect) {
if (!isActive() && titleTimer == 0.0f)
return;
@@ -1437,17 +1494,7 @@ struct Inventory {
Core::mLightProj.identity();
Core::mView.identity();
Core::mView.translate(vec3(-Core::eye * 8.0f, 0, -1286)); // y = -96 in title
Core::mView.up() *= -1.0f;
Core::mView.dir() *= -1.0f;
Core::mViewInv = Core::mView.inverseOrtho();
Core::mProj = mat4(70.0f, aspect, 32.0f, 2048.0f);
Core::setViewProj(Core::mView, Core::mProj);
Core::viewPos = Core::mViewInv.getPos();
setupCamera(aspect);
Core::whiteTex->bind(sShadow);
game->setShader(Core::passCompose, Shader::ENTITY, false, false);
@@ -1477,6 +1524,12 @@ struct Inventory {
float eye = UI::width * Core::eye * 0.01f;
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) {
setupCamera(1.0f, true);
Core::active.shader->setParam(uViewProj, Core::mViewProj);
eye = 0.0f;
}
if (!game->getLevel()->isTitle())
UI::textOut(vec2(-eye, 32), pageTitle[page], UI::aCenter, UI::width);
@@ -1490,17 +1543,19 @@ struct Inventory {
UI::textOut(vec2(-eye, 480 - 16), "]", UI::aRight, UI::width - 20);
}
if (index == targetIndex)
renderItemText(items[getGlobalIndex(page, index)]);
if (index == targetIndex && page == targetPage)
renderItemText(eye, items[getGlobalIndex(page, index)]);
// inventory controls help
float dx = 32.0f - eye;
char buf[64];
sprintf(buf, STR[STR_HELP_SELECT], STR[STR_KEY_FIRST + ikEnter] );
UI::textOut(vec2(dx, 480 - 64), buf, UI::aLeft, UI::width);
if (chosen) {
sprintf(buf, STR[STR_HELP_BACK], STR[STR_KEY_FIRST + Core::settings.controls[playerIndex].keys[ cInventory ].key] );
UI::textOut(vec2(0, 480 - 64), buf, UI::aRight, UI::width - dx);
if (page == targetPage) {
float dx = 32.0f - eye;
char buf[64];
sprintf(buf, STR[STR_HELP_SELECT], STR[STR_KEY_FIRST + ikEnter] );
UI::textOut(vec2(dx, 480 - 64), buf, UI::aLeft, UI::width);
if (chosen) {
sprintf(buf, STR[STR_HELP_BACK], STR[STR_KEY_FIRST + Core::settings.controls[playerIndex].keys[ cInventory ].key] );
UI::textOut(vec2(0, 480 - 64), buf, UI::aRight, UI::width - dx);
}
}
}
};

View File

@@ -183,8 +183,8 @@ struct Lara : Character {
#define LARA_RGUN_JOINT 10
#define LARA_LGUN_JOINT 13
#define LARA_RGUN_OFFSET vec3( 10, -50, 0)
#define LARA_LGUN_OFFSET vec3(-10, -50, 0)
#define LARA_RGUN_OFFSET vec3(-10, -50, 0)
#define LARA_LGUN_OFFSET vec3( 10, -50, 0)
enum {
BODY_HIP = 0x0001,
@@ -474,6 +474,7 @@ struct Lara : Character {
if (level->extra.braid > -1)
braid = new Braid(this, (level->version & (TR::VER_TR2 | TR::VER_TR3)) ? vec3(-2.0f, -16.0f, -48.0f) : vec3(-4.0f, 24.0f, -48.0f));
reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool)
#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)
@@ -941,7 +942,8 @@ struct Lara : Character {
shots++;
game->addMuzzleFlash(this, i ? LARA_LGUN_JOINT : LARA_RGUN_JOINT, i ? LARA_LGUN_OFFSET : LARA_RGUN_OFFSET, 1 + camera->cameraIndex);
if (wpnCurrent != Weapon::SHOTGUN)
game->addMuzzleFlash(this, i ? LARA_LGUN_JOINT : LARA_RGUN_JOINT, i ? LARA_LGUN_OFFSET : LARA_RGUN_OFFSET, 1 + camera->cameraIndex);
// TODO: use new trace code
int joint = wpnCurrent == Weapon::SHOTGUN ? 8 : (i ? 11 : 8);
@@ -1151,6 +1153,10 @@ struct Lara : Character {
return vec3(atan2f(dir.y, sqrtf(dir.x * dir.x + dir.z * dir.z)) - angle.x, atan2f(dir.x, dir.z) - angle.y + PI, 0.0f);
}
vec3 getAngleAbs(const vec3 &dir) {
return vec3(-atan2f(dir.y, sqrtf(dir.x * dir.x + dir.z * dir.z)), -atan2f(dir.x, dir.z), 0.0f);
}
virtual void lookAt(Controller *target) {
if (health <= 0.0f)
return;
@@ -1439,10 +1445,8 @@ struct Lara : Character {
flags.invisible = true;
if (!environment)
environment = new Texture(256, 256, Texture::RGBA, Texture::CUBEMAP | Texture::MIPMAPS);
Core::beginFrame();
game->renderEnvironment(getRoomIndex(), pos - vec3(0.0f, 384.0f, 0.0f), &environment, 0, Core::passCompose);
environment->generateMipMap();
Core::endFrame();
flags.invisible = false;
}
@@ -2637,28 +2641,51 @@ struct Lara : Character {
Input::Joystick &joy = Input::joy[Core::settings.controls[pid].joyIndex];
if ((state == STATE_STOP || state == STATE_SURF_TREAD || state == STATE_HANG) && fabsf(joy.L.x) < 0.5f && fabsf(joy.L.y) < 0.5f)
return input;
if (!((state == STATE_STOP || state == STATE_SURF_TREAD || state == STATE_HANG) && fabsf(joy.L.x) < 0.5f && fabsf(joy.L.y) < 0.5f)) {
bool moving = state == STATE_RUN || state == STATE_WALK || state == STATE_BACK || state == STATE_FAST_BACK || state == STATE_SURF_SWIM || state == STATE_SURF_BACK || state == STATE_FORWARD_JUMP;
bool moving = state == STATE_RUN || state == STATE_WALK || state == STATE_BACK || state == STATE_FAST_BACK || state == STATE_SURF_SWIM || state == STATE_SURF_BACK || state == STATE_FORWARD_JUMP;
if (!moving) {
if (fabsf(joy.L.x) < fabsf(joy.L.y))
joy.L.x = 0.0f;
else
joy.L.y = 0.0f;
}
if (!moving) {
if (fabsf(joy.L.x) < fabsf(joy.L.y))
joy.L.x = 0.0f;
else
joy.L.y = 0.0f;
if (joy.L.x != 0.0f) {
input |= (joy.L.x < 0.0f) ? LEFT : RIGHT;
if (moving || stand == STAND_UNDERWATER || stand == STAND_ONWATER)
rotFactor.y = min(fabsf(joy.L.x) / 0.9f, 1.0f);
}
if (joy.L.y != 0.0f) {
input |= (joy.L.y < 0.0f) ? FORTH : BACK;
if (stand == STAND_UNDERWATER)
rotFactor.x = min(fabsf(joy.L.y) / 0.9f, 1.0f);
}
}
if (joy.L.x != 0.0f) {
input |= (joy.L.x < 0.0f) ? LEFT : RIGHT;
if (moving || stand == STAND_UNDERWATER || stand == STAND_ONWATER)
rotFactor.y = min(fabsf(joy.L.x) / 0.9f, 1.0f);
}
// VR control
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR && camera->firstPerson && canFreeRotate()) {
if (!(input & WALK)) {
input &= ~(LEFT | RIGHT);
}
if (joy.L.y != 0.0f) {
input |= (joy.L.y < 0.0f) ? FORTH : BACK;
if (stand == STAND_UNDERWATER)
rotFactor.x = min(fabsf(joy.L.y) / 0.9f, 1.0f);
vec3 ang = getAngleAbs(Input::hmd.head.dir().xyz());
angle.y = ang.y;
// rotFactor = vec2(1.0f);
// ang.y = shortAngle(angle.y, ang.y);
// if (fabsf(ang.y) > 5 * DEG2RAD)
// input |= ang.y < 0.0f ? LEFT : RIGHT;
if (stand == STAND_UNDERWATER) {
input &= ~(FORTH | BACK);
angle.x = ang.x;
// ang.x = shortAngle(angle.x, ang.x);
// if (fabsf(ang.x) > 5 * DEG2RAD)
// input |= ang.x < 0.0f ? FORTH : BACK;
}
}
return input;
@@ -2669,6 +2696,7 @@ struct Lara : Character {
|| state == STATE_DEATH
|| state == STATE_UNDERWATER_DEATH
|| state == STATE_HANG
|| state == STATE_HANG_UP
|| state == STATE_HANG_LEFT
|| state == STATE_HANG_RIGHT
|| state == STATE_PUSH_BLOCK
@@ -2682,9 +2710,12 @@ struct Lara : Character {
|| state == STATE_SPECIAL
|| state == STATE_REACH
|| state == STATE_SWAN_DIVE
|| state == STATE_FAST_DIVE
|| state == STATE_HANDSTAND
|| state == STATE_ROLL_1
|| state == STATE_ROLL_2
|| state == STATE_MIDAS_USE
|| state == STATE_MIDAS_DEATH
// make me sick!
// || state == STATE_BACK_JUMP
// || state == STATE_LEFT_JUMP
@@ -2694,6 +2725,10 @@ struct Lara : Character {
|| animation.index == ANIM_CLIMB_JUMP;
}
bool canFreeRotate() {
return !(useHeadAnimation() || state == STATE_SLIDE || state == STATE_SLIDE_BACK);
}
virtual void doCustomCommand(int curFrame, int prevFrame) {
switch (state) {
case STATE_PICK_UP : {
@@ -2765,7 +2800,7 @@ struct Lara : Character {
else
hit(Core::deltaTime * 150.0f);
} else
if (oxygen < LARA_MAX_OXYGEN)
if (oxygen < LARA_MAX_OXYGEN && health > 0.0f)
oxygen = min(LARA_MAX_OXYGEN, oxygen += Core::deltaTime * 10.0f);
usedKey = TR::Entity::LARA;
@@ -2811,9 +2846,12 @@ struct Lara : Character {
w *= TURN_WATER_FAST;
else if (state == STATE_TREAD || state == STATE_SURF_TREAD || state == STATE_SURF_SWIM || state == STATE_SURF_BACK)
w *= TURN_WATER_FAST;
else if (state == STATE_RUN)
w *= sign(w) != sign(tilt) ? 0.0f : w * TURN_FAST * tilt / LARA_TILT_MAX;
else if (state == STATE_FAST_TURN)
else if (state == STATE_RUN) {
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
w *= TURN_FAST;
else
w *= sign(w) != sign(tilt) ? 0.0f : w * TURN_FAST * tilt / LARA_TILT_MAX;
} else if (state == STATE_FAST_TURN)
w *= TURN_FAST;
else if (state == STATE_FAST_BACK)
w *= TURN_FAST_BACK;
@@ -2928,7 +2966,8 @@ struct Lara : Character {
if (stand == STAND_UNDERWATER)
vTilt *= 2.0f;
vTilt *= rotFactor.y;
updateTilt(state == STATE_RUN || stand == STAND_UNDERWATER, vTilt.x, vTilt.y);
bool VR = (Core::settings.detail.stereo == Core::Settings::STEREO_VR) && camera->firstPerson;
updateTilt((state == STATE_RUN || stand == STAND_UNDERWATER) && !VR, vTilt.x, vTilt.y);
collisionOffset = vec3(0.0f);

View File

@@ -235,6 +235,11 @@ struct Level : IGame {
bool redraw = settings.detail.stereo != Core::settings.detail.stereo;
#ifdef ANDROID
if ((settings.detail.stereo == Core::Settings::STEREO_VR) ^ (Core::settings.detail.stereo == Core::Settings::STEREO_VR))
osToggleVR(settings.detail.stereo == Core::Settings::STEREO_VR);
#endif
Core::settings = settings;
Stream::cacheWrite("settings", (char*)&settings, sizeof(settings));
@@ -611,10 +616,10 @@ struct Level : IGame {
track = TR::LEVEL_INFO[level.id].ambientTrack;
if (level.state.flags.track == track) {
if (sndTrack) {
sndTrack->replay();
sndTrack->setVolume(1.0f, 0.2f);
}
// if (sndTrack) {
// sndTrack->replay();
// sndTrack->setVolume(1.0f, 0.2f);
// }
return;
}
@@ -708,6 +713,10 @@ struct Level : IGame {
camera->doCutscene(lara->pos, lara->angle.y);
}
*/
Core::setTarget(NULL);
Core::validateRenderState();
Core::resetTime();
}
@@ -1206,7 +1215,6 @@ struct Level : IGame {
}
void initReflections() {
Core::beginFrame();
for (int i = 0; i < level.entitiesBaseCount; i++) {
TR::Entity &e = level.entities[i];
if (e.type == TR::Entity::CRYSTAL) {
@@ -1215,7 +1223,6 @@ struct Level : IGame {
c->environment->generateMipMap();
}
}
Core::endFrame();
}
void setMainLight(Controller *controller) {
@@ -1788,6 +1795,24 @@ struct Level : IGame {
}
}
void renderOpaque(int *roomsList, int roomsCount) {
renderRooms(roomsList, roomsCount, 0);
renderEntities(0);
}
void renderTransparent(int *roomsList, int roomsCount) {
renderRooms(roomsList, roomsCount, 1);
renderEntities(1);
}
void renderAdditive(int *roomsList, int roomsCount) {
vec4 oldFog = Core::fogParams;
Core::fogParams = FOG_BLACK; // don't apply fog for additive
renderRooms(roomsList, roomsCount, 2);
renderEntities(2);
Core::fogParams = oldFog;
}
virtual void renderView(int roomIndex, bool water, bool showUI, int roomsCount = 0, int *roomsList = NULL) {
PROFILE_MARKER("VIEW");
@@ -1849,7 +1874,10 @@ struct Level : IGame {
}
if (water) {
Core::setTarget(NULL, (Core::settings.detail.stereo == Core::Settings::STEREO_OFF && players[1] == NULL) ? CLEAR_ALL : 0); // render to back buffer
//bool clear = Core::settings.detail.stereo == Core::Settings::STEREO_VR;
//clear |= Core::settings.detail.stereo == Core::Settings::STEREO_OFF && players[1] == NULL;
bool clear = true;
Core::setTarget(NULL, clear ? CLEAR_ALL : 0); // render to back buffer
setupBinding();
}
@@ -1857,12 +1885,11 @@ struct Level : IGame {
updateLighting();
// opaque pass
renderRooms(roomsList, roomsCount, 0);
renderEntities(0);
// alpha blending pass
renderRooms(roomsList, roomsCount, 1);
renderEntities(1);
renderOpaque(roomsList, roomsCount);
renderTransparent(roomsList, roomsCount);
if (camera->isUnderwater())
renderAdditive(roomsList, roomsCount);
Core::setBlending(bmNone);
if (water && waterCache && waterCache->visible) {
@@ -1875,13 +1902,9 @@ struct Level : IGame {
setupBinding();
}
// additive blending pass
vec4 oldFog = Core::fogParams;
Core::fogParams = FOG_BLACK; // don't apply fog for additive
renderRooms(roomsList, roomsCount, 2);
renderEntities(2);
Core::fogParams = oldFog;
if (!camera->isUnderwater())
renderAdditive(roomsList, roomsCount);
Core::setBlending(bmNone);
if (showUI) {
@@ -1931,7 +1954,9 @@ struct Level : IGame {
void renderShadows(int roomIndex) {
PROFILE_MARKER("PASS_SHADOW");
float oldEye = Core::eye;
Core::eye = 0.0f;
Core::pass = Core::passShadow;
shadow->unbind(sShadow);
bool colorShadow = shadow->format == Texture::RGBA ? true : false;
@@ -1948,13 +1973,15 @@ struct Level : IGame {
Core::setCulling(cfFront);
if (colorShadow)
Core::setClearColor(vec4(0.0f));
Core::eye = oldEye;
}
#ifdef _DEBUG
void renderDebug() {
if (level.isTitle() || inventory.titleTimer > 1.0f) return;
Core::setViewport(0, 0, Core::width, Core::height);
Core::setViewport(Core::x, Core::y, Core::width, Core::height);
camera->setup(true);
if (Input::down[ikF]) {
@@ -2156,28 +2183,34 @@ struct Level : IGame {
#endif
void setViewport(int view, int eye, bool isUI) {
float vX = float(Core::x);
float vY = float(Core::y);
float vW = float(Core::width);
float vH = float(Core::height);
float aspect = vW / vH;
if (Core::defaultTarget) {
vX = 0.0f;
vY = 0.0f;
vW = float(Core::defaultTarget->width);
vH = float(Core::defaultTarget->height);
}
vec4 &vp = Core::viewportDef;
if (players[1] != NULL) {
vp = vec4(vW * 0.5f * view, 0.0f, vW * 0.5f, vH);
vp = vec4(vX + vW * 0.5f * view, vY, vW * 0.5f, vH);
if (Core::settings.detail.stereo != Core::Settings::STEREO_SPLIT)
aspect *= 0.5f;
} else
vp = vec4(0.0f, 0.0f, vW, vH);
switch (eye) {
case -1 : vp = vec4(vp.x - vp.x * 0.5f, vp.y, vp.z * 0.5f, vp.w); break;
case +1 : vp = vec4(vW * 0.5f + vp.x / 2.0f, vp.y, vp.z * 0.5f, vp.w); break;
vp = vec4(vX, vY, vW, vH);
if (Core::settings.detail.stereo != Core::Settings::STEREO_VR) {
switch (eye) {
case -1 : vp = vec4(vX + vp.x - vp.x * 0.5f, vY + vp.y, vp.z * 0.5f, vp.w); break;
case +1 : vp = vec4(vX + vW * 0.5f + vp.x / 2.0f, vY + vp.y, vp.z * 0.5f, vp.w); break;
}
}
Core::eye = float(eye);
@@ -2188,15 +2221,23 @@ struct Level : IGame {
camera->aspect = aspect;
}
void renderGame(bool showUI) {
void renderPrepare() {
Core::invalidateTarget(true, true);
if (ambientCache)
ambientCache->processQueue();
if (shadow)
renderShadows(player->getRoomIndex());
Core::setTarget(NULL, CLEAR_ALL);
Core::validateRenderState();
}
void renderGame(bool showUI) {
//if (Core::settings.detail.stereo || Core::settings.detail.splitscreen) {
Core::setTarget(NULL, CLEAR_ALL);
Core::validateRenderState();
// Core::setTarget(NULL, CLEAR_ALL);
// Core::validateRenderState();
//}
/* // catsuit test
@@ -2215,6 +2256,8 @@ struct Level : IGame {
mesh->renderQuad();
return;
*/
vec4 vp = Core::viewportDef;
int viewsCount = players[1] ? 2 : 1;
for (int view = 0; view < viewsCount; view++) {
player = players[view];
@@ -2224,12 +2267,12 @@ struct Level : IGame {
params->clipSign = 1.0f;
params->waterHeight = params->clipHeight;
if (shadow)
if (shadow && view == 1)
renderShadows(player->getRoomIndex());
if (shadow) shadow->bind(sShadow);
Core::pass = Core::passCompose;
/*
if (view == 0 && Input::hmd.ready) {
Core::settings.detail.vr = true;
@@ -2255,9 +2298,11 @@ struct Level : IGame {
Core::defaultTarget = oldTarget;
Core::setTarget(NULL, CLEAR_ALL);
Core::viewportDef = vp;
}
}
*/
if (Core::settings.detail.stereo == Core::Settings::STEREO_ON) { // left/right SBS stereo
float oldEye = Core::eye;
setViewport(view, -1, false);
setup();
renderView(camera->getRoomIndex(), true, showUI);
@@ -2265,15 +2310,16 @@ struct Level : IGame {
setViewport(view, 1, false);
setup();
renderView(camera->getRoomIndex(), true, showUI);
Core::eye = oldEye;
} else {
setViewport(view, 0, false);
setViewport(view, int(Core::eye), false);
setup();
renderView(camera->getRoomIndex(), true, showUI);
}
}
Core::eye = 0;
Core::viewportDef = vec4(0.0f, 0.0f, float(Core::width), float(Core::height));
Core::viewportDef = vp;
player = players[0];
camera = player->camera;
@@ -2301,18 +2347,27 @@ struct Level : IGame {
float eye = inventory.active ? 0.0f : UI::width * Core::eye * 0.02f;
vec2 pos;
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
pos = vec2((UI::width - size.x) * 0.5f - eye * 4.0f, 96);
else
pos = vec2(UI::width - 32 - size.x - eye, 32);
if (!player->dozy && (player->stand == Lara::STAND_ONWATER || player->stand == Character::STAND_UNDERWATER)) {
UI::renderBar(UI::BAR_OXYGEN, pos, size, oxygen);
pos.y += 16.0f;
}
if ((!inventory.active && (!player->emptyHands() || player->damageTime > 0.0f || health <= 0.2f))) {
UI::renderBar(UI::BAR_HEALTH, vec2(UI::width - 32 - size.x - eye, 32), size, health);
UI::renderBar(UI::BAR_HEALTH, pos, size, health);
pos.y += 32.0f;
if (!inventory.active && !player->emptyHands()) { // ammo
int index = inventory.contains(player->getCurrentWeaponInv());
if (index > -1)
inventory.renderItemCount(inventory.items[index], vec2(UI::width - 32 - size.x - eye, 64), size.x);
inventory.renderItemCount(inventory.items[index], pos, size.x);
}
}
if (!player->dozy && (player->stand == Lara::STAND_ONWATER || player->stand == Character::STAND_UNDERWATER))
UI::renderBar(UI::BAR_OXYGEN, vec2(32 - eye, 32), size, oxygen);
}
if (!level.isTitle())
@@ -2324,11 +2379,12 @@ struct Level : IGame {
void renderInventoryEye(int eye) {
float aspect = float(Core::width) / float(Core::height);
switch (eye) {
case -1 : Core::setViewport(0, 0, Core::width / 2, Core::height); break;
case 0 : Core::setViewport(0, 0, Core::width, Core::height); break;
case +1 : Core::setViewport(Core::width / 2, 0, Core::width / 2, Core::height); break;
}
if (Core::settings.detail.stereo != Core::Settings::STEREO_VR)
switch (eye) {
case -1 : Core::setViewport(Core::x, Core::y, Core::width / 2, Core::height); break;
case 0 : Core::setViewport(Core::x, Core::y, Core::width, Core::height); break;
case +1 : Core::setViewport(Core::x + Core::width / 2, Core::y, Core::width / 2, Core::height); break;
}
if (Core::settings.detail.stereo == Core::Settings::STEREO_SPLIT)
eye = 0;
@@ -2351,14 +2407,16 @@ struct Level : IGame {
if (!(level.isTitle() || inventory.titleTimer > 0.0f))
inventory.renderBackground();
float oldEye = Core::eye;
if ((Core::settings.detail.stereo == Core::Settings::STEREO_ON) || (Core::settings.detail.stereo == Core::Settings::STEREO_SPLIT && players[1])) {
renderInventoryEye(-1);
renderInventoryEye(+1);
} else
renderInventoryEye(0);
renderInventoryEye(int(Core::eye));
Core::setViewport(0, 0, Core::width, Core::height);
Core::eye = 0.0f;
Core::setViewport(Core::x, Core::y, Core::width, Core::height);
Core::eye = oldEye;
}
void render() {

View File

@@ -200,6 +200,7 @@ struct Mesh {
range.bind(VAO);
bind(true);
range.setup(vBuffer);
unbind();
} else
#endif
range.aIndex = -1;
@@ -217,12 +218,21 @@ struct Mesh {
#endif
}
static void unbind() {
if (Core::support.VAO)
glBindVertexArray(Core::active.VAO = 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Core::active.iBuffer = 0);
glBindBuffer(GL_ARRAY_BUFFER, Core::active.vBuffer = 0);
}
void render(const MeshRange &range) {
if (range.aIndex == -1)
bind();
#ifndef _PSP
range.bind(VAO);
#endif
bind();
if (range.aIndex == -1)
range.setup(vBuffer);
@@ -707,7 +717,7 @@ struct MeshBuilder {
#ifdef GENERATE_WATER_PLANE
plane.vStart = vStartCommon;
plane.iStart = iCount;
plane.iCount = PLANE_DETAIL * 2 * PLANE_DETAIL * 2 * (2 * 3);
plane.iCount = SQR(PLANE_DETAIL * 2) * 6;
baseIdx = vCount - vStartCommon;
for (int16 j = -PLANE_DETAIL; j <= PLANE_DETAIL; j++)

View File

@@ -1,11 +1,12 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
compileSdkVersion 26
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "com.xproger.openlara"
minSdkVersion 18
minSdkVersion 19
targetSdkVersion 18
versionCode 1
versionName "0.1"
@@ -36,4 +37,6 @@ android {
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.google.vr:sdk-base:1.80.0'
}

View File

@@ -3,7 +3,7 @@
android:versionCode="1"
android:versionName="0.1" >
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18" />
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="26" />
<supports-screens android:smallScreens="true" android:largeScreens="true" android:normalScreens="true" android:xlargeScreens="true" />
<uses-feature android:glEsVersion="0x00020000" android:required="true" />

View File

@@ -7,6 +7,8 @@
#include "game.h"
JavaVM *jvm;
#define JNI_METHOD(return_type, method_name) \
JNIEXPORT return_type JNICALL \
Java_org_xproger_openlara_Wrapper_##method_name
@@ -29,12 +31,24 @@ void osJoyVibrate(int index, float L, float R) {
//
}
void osToggleVR(bool enable) {
JNIEnv *jniEnv;
jvm->AttachCurrentThread(&jniEnv, NULL);
jboolean v = enable;
jclass c = jniEnv->FindClass("org/xproger/openlara/MainActivity");
jmethodID m = jniEnv->GetStaticMethodID(c, "toggleVR", "(Z)V");
jniEnv->CallStaticVoidMethod(c, m, v);
}
extern "C" {
char Stream::cacheDir[255];
char Stream::contentDir[255];
JNI_METHOD(void, nativeInit)(JNIEnv* env, jobject obj, jstring contentDir, jstring cacheDir) {
env->GetJavaVM(&jvm);
timeval t;
gettimeofday(&t, NULL);
startTime = t.tv_sec;
@@ -51,7 +65,8 @@ JNI_METHOD(void, nativeInit)(JNIEnv* env, jobject obj, jstring contentDir, jstri
strcat(Stream::cacheDir, str);
env->ReleaseStringUTFChars(cacheDir, str);
Game::init();
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&Core::defaultFBO);
Game::init("level/1/LEVEL2.PSX");
}
JNI_METHOD(void, nativeFree)(JNIEnv* env) {
@@ -63,14 +78,29 @@ JNI_METHOD(void, nativeReset)(JNIEnv* env) {
}
JNI_METHOD(void, nativeUpdate)(JNIEnv* env) {
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&Core::defaultFBO);
Game::update();
}
JNI_METHOD(void, nativeRender)(JNIEnv* env) {
Game::render();
JNI_METHOD(void, nativeFrameBegin)(JNIEnv* env) {
Game::frameBegin();
}
JNI_METHOD(void, nativeResize)(JNIEnv* env, jobject obj, jint w, jint h) {
JNI_METHOD(void, nativeFrameEnd)(JNIEnv* env) {
Game::frameEnd();
Core::reset();
}
JNI_METHOD(void, nativeFrameRender)(JNIEnv* env) {
Game::frameRender();
Core::reset();
}
JNI_METHOD(void, nativeResize)(JNIEnv* env, jobject obj, jint x, jint y, jint w, jint h) {
Core::viewportDef = vec4(float(x), float(y), float(w), float(h));
Core::x = x;
Core::y = y;
Core::width = w;
Core::height = h;
}
@@ -101,7 +131,6 @@ JNI_METHOD(void, nativeTouch)(JNIEnv* env, jobject obj, jint id, jint state, jfl
case -4 : Input::setJoyPos(id, jkR, vec2(DeadZone(x), DeadZone(y))); break;
default : {
int btn = int(x);
LOG("key %d = %d\n", btn, state);
if (btn < 0)
Input::setJoyDown(id, JoyKey(jkNone - btn), state != -1);
else
@@ -111,16 +140,6 @@ JNI_METHOD(void, nativeTouch)(JNIEnv* env, jobject obj, jint id, jint state, jfl
return;
}
if (id == -100) {
/*
switch (state) {
case 0 : Input::head.basis.rot.x = x; Input::head.basis.rot.y = y; break;
case 1 : Input::head.basis.rot.z = x; Input::head.basis.rot.w = y; Input::head.set(); break;
}
*/
return;
}
// touch
InputKey key = Input::getTouch(id);
if (key == ikNone) return;
@@ -129,6 +148,37 @@ JNI_METHOD(void, nativeTouch)(JNIEnv* env, jobject obj, jint id, jint state, jfl
Input::setDown(key, state == 2);
}
JNI_METHOD(void, nativeSetVR)(JNIEnv* env, jobject obj, jboolean enabled) {
Core::Settings settings = Core::settings;
settings.detail.stereo = enabled ? Core::Settings::STEREO_VR : Core::Settings::STEREO_OFF;
Game::level->applySettings(settings);
}
JNI_METHOD(void, nativeSetHead)(JNIEnv* env, jobject obj, jfloatArray head) {
jfloat *mHead = env->GetFloatArrayElements(head, NULL);
memcpy(&Input::hmd.head, mHead, sizeof(float) * 16);
Input::hmd.head = Input::hmd.head.inverseOrtho();
env->ReleaseFloatArrayElements(head, mHead, 0);
}
JNI_METHOD(void, nativeSetEye)(JNIEnv* env, jobject obj, jint eye, jfloatArray proj, jfloatArray view) {
Core::eye = float(eye);
if (eye == 0) return;
eye = eye == -1 ? 0 : 1;
jfloat *mProj = env->GetFloatArrayElements(proj, NULL);
jfloat *mView = env->GetFloatArrayElements(view, NULL);
memcpy(&Input::hmd.proj[eye], mProj, sizeof(float) * 16);
memcpy(&Input::hmd.eye[eye], mView, sizeof(float) * 16);
Input::hmd.eye[eye].setPos(Input::hmd.eye[eye].getPos() * ONE_METER);
Input::hmd.eye[eye] = Input::hmd.eye[eye].inverseOrtho();
env->ReleaseFloatArrayElements(proj, mProj, 0);
env->ReleaseFloatArrayElements(view, mView, 0);
}
JNI_METHOD(void, nativeSoundFill)(JNIEnv* env, jobject obj, jshortArray buffer) {
jshort *frames = env->GetShortArrayElements(buffer, NULL);
jsize count = env->GetArrayLength(buffer) / 2;

View File

@@ -2,20 +2,10 @@ package org.xproger.openlara;
import java.util.ArrayList;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.pm.PackageManager;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.os.Bundle;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Environment;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -26,12 +16,24 @@ import android.view.View.OnKeyListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
//import android.util.Log;
public class MainActivity extends Activity implements OnTouchListener, OnKeyListener, OnGenericMotionListener, SensorEventListener {
import com.google.vr.sdk.base.AndroidCompat;
import com.google.vr.sdk.base.Eye;
import com.google.vr.sdk.base.GvrActivity;
import com.google.vr.sdk.base.GvrView;
import com.google.vr.sdk.base.HeadTransform;
import com.google.vr.sdk.base.Viewport;
public class MainActivity extends GvrActivity implements OnTouchListener, OnKeyListener, OnGenericMotionListener {
static GvrView gvrView;
private Wrapper wrapper;
private ArrayList joyList = new ArrayList();
public static void toggleVR(boolean enable) {
gvrView.setStereoModeEnabled(enable);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
@@ -45,10 +47,11 @@ public class MainActivity extends Activity implements OnTouchListener, OnKeyList
super.onCreate(savedInstanceState);
GLSurfaceView view = new GLSurfaceView(this);
//GLSurfaceView view = new GLSurfaceView(this);
final GvrView view = new GvrView(this);
view.setEGLContextClientVersion(2);
view.setEGLConfigChooser(8, 8, 8, 8, 16, 8);
view.setPreserveEGLContextOnPause(true);
//view.setPreserveEGLContextOnPause(true);
view.setRenderer(wrapper = new Wrapper());
view.setFocusable(true);
@@ -57,13 +60,30 @@ public class MainActivity extends Activity implements OnTouchListener, OnKeyList
view.setOnTouchListener(this);
view.setOnGenericMotionListener(this);
view.setOnKeyListener(this);
//setAsyncReprojectionEnabled(true);
//setSustainedPerformanceMode(this, true);
view.setTransitionViewEnabled(false);
if (view.setAsyncReprojectionEnabled(true)) {
AndroidCompat.setSustainedPerformanceMode(this, true);
}
//AndroidCompat.setVrModeEnabled(this, false);
view.setStereoModeEnabled(false);
view.setDistortionCorrectionEnabled(true);
view.setOnCloseButtonListener(new Runnable() {
@Override
public void run() {
view.setStereoModeEnabled(false);
wrapper.toggleVR = true;
}
});
setGvrView(view);
setContentView(view);
/*
SensorManager sm = (SensorManager)getSystemService(SENSOR_SERVICE);
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR), SensorManager.SENSOR_DELAY_FASTEST);
*/
gvrView = view;
try {
String content = Environment.getExternalStorageDirectory().getAbsolutePath();
wrapper.onCreate(content + "/OpenLara/", getCacheDir().getAbsolutePath() + "/");
@@ -115,16 +135,6 @@ public class MainActivity extends Activity implements OnTouchListener, OnKeyList
return true;
}
@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
}
@Override
public void onSensorChanged(SensorEvent event) {
wrapper.onTouch(-100, 0, -event.values[1], event.values[0]);
wrapper.onTouch(-100, 1, event.values[2], event.values[3]);
}
boolean isGamepad(int src) {
return (src & (InputDevice.SOURCE_GAMEPAD | InputDevice.SOURCE_JOYSTICK)) != 0;
}
@@ -285,17 +295,23 @@ class Touch {
}
}
class Wrapper implements Renderer {
class Wrapper implements GvrView.StereoRenderer {
public static native void nativeInit(String contentDir, String cacheDir);
public static native void nativeFree();
public static native void nativeReset();
public static native void nativeResize(int w, int h);
public static native void nativeResize(int x, int y, int w, int h);
public static native void nativeUpdate();
public static native void nativeRender();
public static native void nativeSetVR(boolean enabled);
public static native void nativeSetHead(float head[]);
public static native void nativeSetEye(int eye, float proj[], float view[]);
public static native void nativeFrameBegin();
public static native void nativeFrameEnd();
public static native void nativeFrameRender();
public static native void nativeTouch(int id, int state, float x, float y);
public static native void nativeSoundFill(short buffer[]);
Boolean ready = false;
Boolean toggleVR = false;
private String contentDir;
private String cacheDir;
private ArrayList<Touch> touch = new ArrayList<>();
@@ -330,7 +346,26 @@ class Wrapper implements Renderer {
}
@Override
public void onDrawFrame(GL10 gl) {
public void onSurfaceChanged(int width, int height) {
nativeResize(0, 0, width, height);
}
@Override
public void onSurfaceCreated(EGLConfig config) {
if (!ready) {
nativeInit(contentDir, cacheDir);
sound.play();
ready = true;
}
}
@Override
public void onRendererShutdown() {
//
}
@Override
public void onNewFrame(HeadTransform headTransform) {
synchronized (this) {
for (int i = 0; i < touch.size(); i++) {
Touch t = touch.get(i);
@@ -338,21 +373,37 @@ class Wrapper implements Renderer {
}
touch.clear();
}
nativeUpdate();
nativeRender();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
nativeResize(width, height);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
if (!ready) {
nativeInit(contentDir, cacheDir);
sound.play();
ready = true;
if (toggleVR) {
nativeSetVR(false);
toggleVR = false;
}
float view[] = headTransform.getHeadView();
nativeSetHead(view);
nativeUpdate();
nativeFrameBegin();
}
@Override
public void onDrawEye(Eye eye) {
float proj[] = eye.getPerspective(8.0f, 32.0f * 1024.0f);
float view[] = eye.getEyeView();
int index = 0;
if (eye.getType() == Eye.Type.LEFT) index = -1;
if (eye.getType() == Eye.Type.RIGHT) index = +1;
nativeSetEye(index, proj, view);
nativeResize(eye.getViewport().x, eye.getViewport().y, eye.getViewport().width, eye.getViewport().height);
nativeFrameRender();
}
@Override
public void onFinishFrame(Viewport viewport) {
nativeResize(viewport.x, viewport.y, viewport.width, viewport.height);
nativeFrameEnd();
}
}

View File

@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.android.tools.build:gradle:3.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

@@ -1,5 +1,6 @@
#Tue Mar 20 22:10:10 MSK 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

View File

@@ -605,7 +605,6 @@ void vrUpdateView() {
mat4 vL = head * convToMat4(hmd->GetEyeToHeadTransform(vr::Eye_Left));
mat4 vR = head * convToMat4(hmd->GetEyeToHeadTransform(vr::Eye_Right));
const float ONE_METER = 768.0f / 1.8f; // Lara's height in units / height in meters
vL.setPos(vL.getPos() * ONE_METER);
vR.setPos(vR.getPos() * ONE_METER);

View File

@@ -215,6 +215,7 @@ struct MuzzleFlash : Controller {
MuzzleFlash(IGame *game, int entity) : Controller(game, entity), owner(NULL), joint(0), lightIndex(-1) {
pos.z += (level->version & (TR::VER_TR2 | TR::VER_TR3)) ? 180.0f : 150.0f;
activate();
timer = 0.0f;
}
virtual void update() {

View File

@@ -2,6 +2,7 @@
#define H_UI
#include "core.h"
#include "mesh.h"
#include "controller.h"
enum StringID {
@@ -13,6 +14,7 @@ enum StringID {
, STR_OFF
, STR_ON
, STR_SPLIT
, STR_VR
, STR_QUALITY_LOW
, STR_QUALITY_MEDIUM
, STR_QUALITY_HIGH
@@ -122,6 +124,7 @@ const char *STR[STR_MAX] = {
, "Off"
, "On"
, "Split Screen"
, "VR"
, "Low"
, "Medium"
, "High"