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

#15 core stats refactoring; gamepad analog fix for web; shadow matrix crop (test)

This commit is contained in:
XProger
2017-03-16 18:21:51 +03:00
parent fd89ab526c
commit f8bd8789a7
11 changed files with 320 additions and 190 deletions

View File

@@ -254,6 +254,10 @@ struct Camera : Controller {
updateListener();
}
mat4 getProjMatrix() {
return mat4(fov, (float)Core::width / (float)Core::height, znear, zfar);
}
virtual void setup(bool calcMatrices) {
if (calcMatrices) {
if (reflectPlane) {
@@ -263,7 +267,7 @@ struct Camera : Controller {
Core::mViewInv = mViewInv;
Core::mView = Core::mViewInv.inverse();
Core::mProj = mat4(fov, (float)Core::width / (float)Core::height, znear, zfar);
Core::mProj = getProjMatrix();
// TODO: camera shake
// TODO: temporal anti-aliasing

View File

@@ -541,7 +541,7 @@ struct Controller {
entity.flags.rendered = true;
if (Core::frameIndex != frameIndex)
if (Core::stats.frame != frameIndex)
animation.getJoints(matrix, -1, true, joints);
if (layers) {
@@ -563,7 +563,7 @@ struct Controller {
mesh->renderModel(entity.modelIndex - 1);
}
frameIndex = Core::frameIndex;
frameIndex = Core::stats.frame;
// blob shadow // TODO: fake AO
if (!Core::settings.shadows && Core::pass == Core::passCompose && TR::castShadow(entity.type)) {

View File

@@ -186,9 +186,10 @@ struct Texture;
enum CullMode { cfNone, cfBack, cfFront };
enum BlendMode { bmNone, bmAlpha, bmAdd, bmMultiply, bmScreen };
extern int getTime();
namespace Core {
int width, height;
int frameIndex;
float deltaTime;
mat4 mView, mProj, mViewProj, mViewInv, mLightProj;
Basis basis;
@@ -221,9 +222,24 @@ namespace Core {
CullMode cullMode;
} active;
struct {
int dips;
int tris;
struct Stats {
int dips, tris, frame, fps, fpsTime;
Stats() : frame(0), fps(0), fpsTime(0) {}
void start() {
dips = tris = 0;
}
void stop() {
if (fpsTime < getTime()) {
LOG("FPS: %d DIP: %d TRI: %d\n", fps, dips, tris);
fps = frame;
frame = 0;
fpsTime = getTime() + 1000;
} else
frame++;
}
} stats;
struct {
@@ -360,8 +376,6 @@ namespace Core {
for (int i = 0; i < MAX_LIGHTS; i++)
lightColor[i] = vec4(0, 0, 0, 1);
frameIndex = 0;
uint32 data = 0x00000000;
blackTex = new Texture(1, 1, Texture::RGBA, false, &data, false);
@@ -532,13 +546,18 @@ namespace Core {
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);
}
void resetStates() {
void beginFrame() {
memset(&active, 0, sizeof(active));
setDepthTest(true);
active.blendMode = bmAlpha;
active.cullMode = cfNone;
setCulling(cfFront);
setBlending(bmNone);
Core::stats.start();
}
void endFrame() {
Core::stats.stop();
}
}

View File

@@ -60,8 +60,9 @@ namespace Game {
}
void render() {
Core::beginFrame();
level->render();
Core::frameIndex++;
Core::endFrame();
}
}

View File

@@ -54,7 +54,7 @@ struct Lara : Character {
ANIM_STAND_RIGHT = 3,
ANIM_STAND = 11,
ANIM_CLIMB_JUMP = 26,
ANIM_HANG_FALL = 28,
@@ -159,7 +159,7 @@ struct Lara : Character {
STATE_HANDSTAND,
STATE_WATER_OUT,
STATE_MAX };
enum : int {
BODY_HIP = 0x0001,
BODY_LEG_L1 = 0x0002,
@@ -209,7 +209,7 @@ struct Lara : Character {
} arms[2];
ActionCommand actionList[MAX_TRIGGER_ACTIONS];
Inventory inventory;
int lastPickUp;
int viewTarget;
@@ -272,10 +272,10 @@ struct Lara : Character {
float DAMPING = 1.5f;
if (lara->getRoom().flags.water) {
ACCEL *= -0.5f;
ACCEL *= -0.5f;
DAMPING = 4.0f;
}
DAMPING = 1.0f / (1.0f + DAMPING * TIMESTEP); // Pade approximation
for (int i = 1; i < jointsCount; i++) {
@@ -340,7 +340,7 @@ struct Lara : Character {
a.pos -= dir;
b.pos += dir;
} else
b.pos += dir * (d * 1.0f);
b.pos += dir * (d * 1.0f);
}
}
@@ -349,7 +349,7 @@ struct Lara : Character {
integrate(); // Verlet integration step
collide(); // check collision with Lara's mesh
for (int i = 0; i < jointsCount; i++) // solve connections (springs)
solve();
solve();
vec3 headDir = getBasis().rot * vec3(0.0f, 0.0f, -1.0f);
@@ -357,13 +357,13 @@ struct Lara : Character {
vec3 d = (joints[i + 1].pos - joints[i].pos).normal();
vec3 r = d.cross(headDir).normal();
vec3 u = d.cross(r).normal();
mat4 m;
m.up = vec4(u, 0.0f);
m.dir = vec4(d, 0.0f);
m.right = vec4(r, 0.0f);
m.offset = vec4(0.0f, 0.0f, 0.0f, 1.0f);
basis[i].identity();
basis[i].translate(joints[i].pos);
basis[i].rotate(m.getRot());
@@ -374,11 +374,11 @@ struct Lara : Character {
Core::active.shader->setParam(uBasis, basis[0], jointsCount);
mesh->renderModel(lara->level->extra.braid);
}
} *braid;
Lara(IGame *game, int entity, bool home) : Character(game, entity, 1000), home(home), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), viewTarget(-1), braid(NULL) {
if (getEntity().type == TR::Entity::LARA) {
if (getRoom().flags.water)
animation.setAnim(ANIM_UNDERWATER);
@@ -408,7 +408,7 @@ struct Lara : Character {
if (level->extra.braid > -1)
braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
#ifdef _DEBUG
#ifdef _DEBUG
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, true); // gym (pool)
//reset(14, vec3(20215, 6656, 52942), PI); // level 1 (bridge)
@@ -443,7 +443,7 @@ struct Lara : Character {
}
updateEntity();
}
void wpnSet(Weapon::Type wType) {
wpnCurrent = wType;
wpnState = Weapon::IS_FIRING;
@@ -463,9 +463,9 @@ struct Lara : Character {
arm.anim = wAnim;
if (wAnimDir > 0.0f)
if (wAnimDir > 0.0f)
arm.animation.time = wAnimTime;
else
else
if (wAnimDir < 0.0f)
arm.animation.time = arm.animation.timeMax + wAnimTime;
arm.animation.updateInfo();
@@ -490,7 +490,7 @@ struct Lara : Character {
int mask = 0;
switch (wpnCurrent) {
case Weapon::EMPTY : break;
case Weapon::PISTOLS :
case Weapon::PISTOLS :
case Weapon::MAGNUMS :
case Weapon::UZIS :
switch (wState) {
@@ -518,7 +518,7 @@ struct Lara : Character {
// 2 - shotgun (hands, chest)
// 3 - angry (head)
// swap weapon parts
// swap weapon parts
if (wpnCurrent != Weapon::SHOTGUN) {
meshSwap(1, level->extra.weapons[wpnCurrent], mask);
// have a shotgun in inventory place it on the back if another weapon is in use
@@ -529,7 +529,7 @@ struct Lara : Character {
// mesh swap to angry Lara's head while firing (from uzis model)
meshSwap(3, level->extra.weapons[Weapon::UZIS], (wState == Weapon::IS_FIRING) ? BODY_HEAD : 0);
wpnState = wState;
}
@@ -538,7 +538,7 @@ struct Lara : Character {
}
bool canLookAt() {
return (stand == STAND_GROUND || stand == STAND_SLIDE)
return (stand == STAND_GROUND || stand == STAND_SLIDE)
&& state != STATE_REACH
&& state != STATE_PUSH_BLOCK
&& state != STATE_PULL_BLOCK
@@ -551,7 +551,7 @@ struct Lara : Character {
&& emptyHands()
&& animation.index != ANIM_CLIMB_3
&& animation.index != ANIM_CLIMB_2
&& state != STATE_DEATH
&& state != STATE_DEATH
&& state != STATE_HANG
&& state != STATE_REACH
&& state != STATE_TREAD
@@ -595,7 +595,7 @@ struct Lara : Character {
wpnSetAnim(arms[0], wpnState, Weapon::Anim::PREPARE, 0.0f, 1.0f);
wpnSetAnim(arms[1], wpnState, Weapon::Anim::PREPARE, 0.0f, 1.0f);
} else
wpnSetAnim(arms[0], wpnState, Weapon::Anim::UNHOLSTER, 0.0f, 1.0f);
wpnSetAnim(arms[0], wpnState, Weapon::Anim::UNHOLSTER, 0.0f, 1.0f);
}
}
@@ -621,7 +621,7 @@ struct Lara : Character {
case Weapon::Anim::PREPARE : ASSERT(false); break; // rifle has no prepare animation
case Weapon::Anim::UNHOLSTER : return 1;
case Weapon::Anim::HOLSTER : return 3;
case Weapon::Anim::HOLD :
case Weapon::Anim::HOLD :
case Weapon::Anim::AIM : return 0;
case Weapon::Anim::FIRE : return 2;
default : ;
@@ -631,7 +631,7 @@ struct Lara : Character {
case Weapon::Anim::PREPARE : return 1;
case Weapon::Anim::UNHOLSTER : return 2;
case Weapon::Anim::HOLSTER : ASSERT(false); break; // pistols has no holster animation (it's reversed unholster)
case Weapon::Anim::HOLD :
case Weapon::Anim::HOLD :
case Weapon::Anim::AIM : return 0;
case Weapon::Anim::FIRE : return 3;
default : ;
@@ -663,7 +663,7 @@ struct Lara : Character {
wpnSetAnim(arms[i], Weapon::IS_ARMED, Weapon::Anim::AIM, 0.0f, -1.0f, target == -1);
}
// shotgun reload sound
if (wpnCurrent == Weapon::SHOTGUN) {
if (wpnCurrent == Weapon::SHOTGUN) {
if (anim.frameIndex == 10)
playSound(TR::SND_SHOTGUN_RELOAD, pos, Sound::Flags::PAN);
}
@@ -681,12 +681,12 @@ struct Lara : Character {
void doShot(bool rightHand, bool leftHand) {
int count = wpnCurrent == Weapon::SHOTGUN ? 6 : 2;
float nearDist = 32.0f * 1024.0f;
vec3 nearPos;
bool hasShot = false;
for (int i = 0; i < count; i++) {
for (int i = 0; i < count; i++) {
int armIndex;
if (wpnCurrent == Weapon::SHOTGUN) {
if (!rightHand) continue;
@@ -696,7 +696,7 @@ struct Lara : Character {
armIndex = i;
}
Arm *arm = &arms[armIndex];
arm->shotTimer = 0.0f;
hasShot = true;
@@ -786,12 +786,12 @@ struct Lara : Character {
float intensity = clamp((0.1f - arms[i].shotTimer) * 20.0f, 0.0f, 1.0f);
Core::lightColor[1 + i] = FLASH_LIGHT_COLOR * vec4(intensity, intensity, intensity, sqrtf(intensity));
}
if (isRifle)
animateShotgun();
else
animatePistols();
wpnFire(); // make a shot
}
}
@@ -800,7 +800,7 @@ struct Lara : Character {
for (int i = 0; i < 2; i++) {
Arm &arm = arms[i];
if (!arm.animation.isEnded) continue;
if (!arm.animation.isEnded) continue;
if (arm.animation.dir >= 0.0f)
switch (arm.anim) {
@@ -815,7 +815,7 @@ struct Lara : Character {
break;
default : ;
};
if (arm.animation.dir < 0.0f)
switch (arm.anim) {
case Weapon::Anim::PREPARE : wpnSetAnim(arm, Weapon::IS_HIDDEN, Weapon::Anim::NONE, 0.0f, 1.0f, false); break;
@@ -842,7 +842,7 @@ struct Lara : Character {
break;
default : ;
}
} else
} else
if (arm.animation.frameIndex != arm.animation.framePrev) {
float delta = arm.animation.time / arm.animation.timeMax;
switch (arm.anim) {
@@ -857,11 +857,11 @@ struct Lara : Character {
}
void updateOverrides() {
// head & chest
// head & chest
animation.overrideMask |= BODY_CHEST | BODY_HEAD;
animation.overrides[ 7] = animation.getJointRot( 7);
animation.overrides[14] = animation.getJointRot(14);
animation.overrides[14] = animation.getJointRot(14);
/* TODO: shotgun full body animation
if (wpnCurrent == Weapon::SHOTGUN) {
@@ -889,14 +889,14 @@ struct Lara : Character {
lookAt(viewTarget);
if (wpnCurrent == Weapon::SHOTGUN)
aimShotgun();
else
aimPistols();
}
void lookAt(int target) { // TODO: character lookAt
void lookAt(int target) { // TODO: character lookAt
float speed = 8.0f * Core::deltaTime;
quat rot;
@@ -904,7 +904,7 @@ struct Lara : Character {
// chest
if (can && aim(target, 7, vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.9f, PI * 0.9f), rot))
rotChest = rotChest.slerp(quat(0, 0, 0, 1).slerp(rot, 0.5f), speed);
else
else
rotChest = rotChest.slerp(quat(0, 0, 0, 1), speed);
animation.overrides[7] = rotChest * animation.overrides[7];
@@ -1010,7 +1010,7 @@ struct Lara : Character {
} else
return false;
}
virtual void cmdEmpty() {
wpnHide();
}
@@ -1034,7 +1034,7 @@ struct Lara : Character {
switch (fx) {
case TR::EFFECT_FLIP_MAP : break; // TODO
case TR::EFFECT_LARA_HANDSFREE : break;//meshSwap(1, level->extra.weapons[wpnCurrent], BODY_LEG_L1 | BODY_LEG_R1); break;
case TR::EFFECT_DRAW_RIGHTGUN :
case TR::EFFECT_DRAW_RIGHTGUN :
case TR::EFFECT_DRAW_LEFTGUN : drawGun(fx == TR::EFFECT_DRAW_RIGHTGUN); break;
default : LOG("unknown effect command %d (anim %d)\n", fx, animation.index);
}
@@ -1094,7 +1094,7 @@ struct Lara : Character {
pos -= getDir() * 256.0f;
pos.y -= 256;
}
updateEntity();
updateEntity();
return true;
}
}
@@ -1109,8 +1109,8 @@ struct Lara : Character {
bool useItem(TR::Entity::Type item, TR::Entity::Type slot) {
if (item == TR::Entity::NONE) {
switch (slot) {
case TR::Entity::HOLE_KEY : item = TR::Entity::KEY_1; break; // TODO: 1-4
case TR::Entity::HOLE_PUZZLE : item = TR::Entity::PUZZLE_1; break;
case TR::Entity::HOLE_KEY : item = TR::Entity::KEY_1; break; // TODO: 1-4
case TR::Entity::HOLE_PUZZLE : item = TR::Entity::PUZZLE_1; break;
default : return false;
}
}
@@ -1269,13 +1269,13 @@ struct Lara : Character {
if (stand == STAND_SLIDE || (stand == STAND_AIR && velocity.y > 0) || stand == STAND_GROUND) {
if (e.y + 8 >= info.floor && (abs(info.slantX) > 2 || abs(info.slantZ) > 2)) {
if (stand == STAND_AIR)
playSound(TR::SND_LANDING, pos, Sound::Flags::PAN);
playSound(TR::SND_LANDING, pos, Sound::Flags::PAN);
pos.y = float(info.floor);
updateEntity();
if (stand == STAND_GROUND || stand == STAND_AIR)
slideStart();
return STAND_SLIDE;
}
}
@@ -1314,7 +1314,7 @@ struct Lara : Character {
vec3 p = vec3(pos.x, bounds.min.y, pos.z);
Collision c = Collision(level, getRoomIndex(), p, getDir() * 32.0f, vec3(0.0f), LARA_RADIUS, angleExt, 0, 0, 0, 0);
if (c.side != Collision::FRONT)
return state;
@@ -1343,7 +1343,7 @@ struct Lara : Character {
if (input & ACTION) return STATE_REACH;
if ((input & (FORTH | WALK)) == (FORTH | WALK)) return STATE_SWAN_DIVE;
}
} else
} else
if (state != STATE_SWAN_DIVE && state != STATE_REACH && state != STATE_FALL && state != STATE_UP_JUMP && state != STATE_BACK_JUMP && state != STATE_LEFT_JUMP && state != STATE_RIGHT_JUMP)
return animation.setAnim(ANIM_FALL);
@@ -1373,7 +1373,7 @@ struct Lara : Character {
for (int i = 0; i < level->entitiesCount; i++) {
TR::Entity &e = level->entities[i];
int q = entityQuadrant(e);
int dx = abs(int(pos.x) - e.x);
int dz = abs(int(pos.z) - e.z);
@@ -1394,10 +1394,10 @@ struct Lara : Character {
if ((input & ACTION) && emptyHands() && doPickUp())
return STATE_PICK_UP;
if ((input & (FORTH | ACTION)) == (FORTH | ACTION) && (animation.index == ANIM_STAND || animation.index == ANIM_STAND_NORMAL) && emptyHands() && collision.side == Collision::FRONT) { // TODO: get rid of animation.index
if ((input & (FORTH | ACTION)) == (FORTH | ACTION) && (animation.index == ANIM_STAND || animation.index == ANIM_STAND_NORMAL) && emptyHands() && collision.side == Collision::FRONT) { // TODO: get rid of animation.index
int floor = collision.info[Collision::FRONT].floor;
int h = (int)pos.y - floor;
int aIndex = animation.index;
if (h <= 2 * 256 + 128) {
aIndex = ANIM_CLIMB_2;
@@ -1406,7 +1406,7 @@ struct Lara : Character {
aIndex = ANIM_CLIMB_3;
pos.y = floor + 768.0f;
} else if (h <= 7 * 256 + 128)
aIndex = ANIM_CLIMB_JUMP;
aIndex = ANIM_CLIMB_JUMP;
if (aIndex != animation.index) {
alignToWall(-LARA_RADIUS);
@@ -1429,29 +1429,29 @@ struct Lara : Character {
}
// jump button is pressed
if (input & JUMP) {
if (input & JUMP) {
if ((input & FORTH) && state == STATE_FORWARD_JUMP)
return STATE_RUN;
if (state == STATE_RUN)
return STATE_FORWARD_JUMP;
if (animation.index == ANIM_SLIDE_BACK) // TODO: animation index? %)
return STATE_SLIDE_BACK;
return STATE_SLIDE_BACK;
return STATE_COMPRESS;
}
// walk button is pressed
if (input & WALK) {
if (input & WALK) {
if (input & FORTH) return STATE_WALK;
if (input & BACK) return STATE_BACK;
if (input & LEFT) return STATE_STEP_LEFT;
if (input & RIGHT) return STATE_STEP_RIGHT;
return STATE_STOP;
}
}
if ((input & ACTION) && emptyHands()) {
if (state == STATE_PUSH_PULL_READY && (input & (FORTH | BACK))) {
int pushState = (input & FORTH) ? STATE_PUSH_BLOCK : STATE_PULL_BLOCK;
Block *block = getBlock();
Block *block = getBlock();
if (animation.canSetState(pushState) && block->doMove((input & FORTH) != 0)) {
alignToWall(-LARA_RADIUS);
return pushState;
@@ -1519,7 +1519,7 @@ struct Lara : Character {
vec3 p = pos + getDir() * (LARA_RADIUS + 2.0f);
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.y, (int)p.z, info);
if (info.floor - info.ceiling >= LARA_HEIGHT)
return (input & WALK) ? STATE_HANDSTAND : STATE_HANG_UP;
return (input & WALK) ? STATE_HANDSTAND : STATE_HANG_UP;
}
return STATE_HANG;
}
@@ -1535,16 +1535,16 @@ struct Lara : Character {
angle.x = -45.0f * DEG2RAD;
return animation.setAnim(ANIM_WATER_FALL); // TODO: wronng animation
}
if (state == STATE_SWAN_DIVE) {
angle.x = -PI * 0.5f;
game->waterDrop(pos, 128.0f, 0.2f);
Sprite::add(game, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
return STATE_DIVE;
}
if (input & JUMP) return STATE_SWIM;
if (state == STATE_GLIDE && speed < LARA_SWIM_SPEED * 2.0f / 3.0f)
return STATE_TREAD;
@@ -1552,7 +1552,7 @@ struct Lara : Character {
}
virtual int getStateOnwater() {
angle.x = 0.0f;
angle.x = 0.0f;
if (state == STATE_WATER_OUT) return state;
@@ -1571,7 +1571,7 @@ struct Lara : Character {
}
if (input & FORTH) {
if (input & JUMP) {
if (input & JUMP) {
angle.x = -PI * 0.25f;
game->waterDrop(pos, 256.0f, 0.2f);
return animation.setAnim(ANIM_TO_UNDERWATER);
@@ -1584,11 +1584,11 @@ struct Lara : Character {
return STATE_SURF_SWIM;
}
if (input & BACK) return STATE_SURF_BACK;
if (input & WALK) {
if (input & LEFT) return STATE_SURF_LEFT;
if (input & RIGHT) return STATE_SURF_RIGHT;
if (input & RIGHT) return STATE_SURF_RIGHT;
}
return STATE_SURF_TREAD;
}
@@ -1636,32 +1636,33 @@ struct Lara : Character {
if (Input::down[ikE] || Input::down[ikCtrl] || Input::down[ikJoyA]) input |= ACTION;
if (Input::down[ikQ] || Input::down[ikAlt] || Input::down[ikJoyY]) input |= WEAPON;
// analog control
rotFactor = vec2(1.0f);
// analog control
rotFactor = vec2(1.0f);
if (Input::down[ikJoyL]) input = FORTH | BACK;
if (Input::down[ikJoyL]) input = FORTH | BACK;
if ((state == STATE_STOP || stand == STATE_SURF_TREAD) && fabsf(Input::joy.L.x) < 0.5f && fabsf(Input::joy.L.y) < 0.5f)
return input;
if ((state == STATE_STOP || state == STATE_SURF_TREAD || state == STATE_HANG) && fabsf(Input::joy.L.x) < 0.5f && fabsf(Input::joy.L.y) < 0.5f)
return input;
bool moving = state == STATE_RUN || state == STATE_WALK || state == STATE_BACK || state == STATE_FAST_BACK || state == STATE_SURF_SWIM || state == STATE_SURF_BACK;
if (!moving)
if (fabsf(Input::joy.L.x) < fabsf(Input::joy.L.y))
Input::joy.L.x = 0.0f;
else
Input::joy.L.y = 0.0f;
if (!moving) {
if (fabsf(Input::joy.L.x) < fabsf(Input::joy.L.y))
Input::joy.L.x = 0.0f;
else
Input::joy.L.y = 0.0f;
}
if (Input::joy.L.x != 0.0f) {
input |= (Input::joy.L.x < 0.0f) ? LEFT : RIGHT;
if (moving || stand == STAND_UNDERWATER || stand == STAND_ONWATER)
rotFactor.y = min(fabsf(Input::joy.L.x) / 0.75f, 1.0f);
}
if (Input::joy.L.x != 0.0f) {
input |= (Input::joy.L.x < 0.0f) ? LEFT : RIGHT;
if (moving || stand == STAND_UNDERWATER || stand == STAND_ONWATER)
rotFactor.y = min(fabsf(Input::joy.L.x) / 0.75f, 1.0f);
}
if (Input::joy.L.y != 0.0f) {
input |= (Input::joy.L.y < 0.0f) ? FORTH : BACK;
if (stand == STAND_UNDERWATER)
rotFactor.x = min(fabsf(Input::joy.L.y) / 0.75f, 1.0f);
if (Input::joy.L.y != 0.0f) {
input |= (Input::joy.L.y < 0.0f) ? FORTH : BACK;
if (stand == STAND_UNDERWATER)
rotFactor.x = min(fabsf(Input::joy.L.y) / 0.75f, 1.0f);
}
return input;
@@ -1672,7 +1673,7 @@ struct Lara : Character {
case STATE_PICK_UP : {
TR::Entity &item = level->entities[lastPickUp];
if (!item.flags.invisible) {
int pickupFrame = stand == STAND_GROUND ? PICKUP_FRAME_GROUND : PICKUP_FRAME_UNDERWATER;
int pickupFrame = stand == STAND_GROUND ? PICKUP_FRAME_GROUND : PICKUP_FRAME_UNDERWATER;
if (animation.isFrameActive(pickupFrame)) {
item.flags.invisible = true;
inventory.add(item.type, 1);
@@ -1716,10 +1717,10 @@ struct Lara : Character {
else if (state == STATE_FAST_BACK)
w *= TURN_FAST_BACK;
else if (state == STATE_TURN_LEFT || state == STATE_TURN_RIGHT || state == STATE_WALK)
w *= TURN_NORMAL;
w *= TURN_NORMAL;
else if (state == STATE_FORWARD_JUMP || state == STATE_BACK)
w *= TURN_SLOW;
else
else
w = 0.0f;
if (w != 0.0f)
@@ -1736,7 +1737,7 @@ struct Lara : Character {
case STATE_BACK_JUMP :
case STATE_FAST_BACK :
case STATE_SLIDE_BACK :
case STATE_ROLL_1 :
case STATE_ROLL_1 :
angleExt += PI;
break;
case STATE_LEFT_JUMP :
@@ -1766,7 +1767,7 @@ struct Lara : Character {
case STATE_SURF_SWIM :
case STATE_SURF_BACK :
case STATE_SURF_LEFT :
case STATE_SURF_RIGHT :
case STATE_SURF_RIGHT :
speed = min(speed + 30.0f * LARA_WATER_ACCEL * Core::deltaTime, LARA_SURF_SPEED);
break;
default :
@@ -1817,7 +1818,7 @@ struct Lara : Character {
if (velocity.length() >= 1.0f)
move();
if (getEntity().type != TR::Entity::LARA) {
TR::Entity &e = getEntity();
vec3 &p = getPos();
@@ -1827,9 +1828,9 @@ struct Lara : Character {
checkRoom();
updateEntity();
}
if (braid)
braid->update();
braid->update();
}
virtual vec3& getPos() {
@@ -1839,7 +1840,7 @@ struct Lara : Character {
void move() {
//TR::Entity &e = getEntity();
//TR::Level::FloorInfo info;
//float f, c;
//bool canPassGap = true;
/*
@@ -1899,7 +1900,7 @@ struct Lara : Character {
}
if (stand == STAND_HANG && collision.side != Collision::FRONT) {
offset.x = offset.z = 0.0f;
offset.x = offset.z = 0.0f;
minHeight = LARA_HANG_OFFSET;
maxDescent = 0xFFFFFF;
maxAscent = -LARA_HANG_OFFSET;
@@ -1932,10 +1933,10 @@ struct Lara : Character {
}
}
}
// check entities in the room
if (canPassGap)
for (int i = 0; i < level->entitiesCount; i++)
for (int i = 0; i < level->entitiesCount; i++)
if (i != entity && level->entities[i].room == e.room && level->entities[i].controller) {
Box mBox = ((Controller*)level->entities[i].controller)->getBoundingBox();
if (eBox.intersect(mBox)) {
@@ -1951,7 +1952,7 @@ struct Lara : Character {
if (state == STATE_WALK) rightStart = 13;
if (state == STATE_BACK) rightStart = 28;
bool isLeftFoot = animation.frameIndex < rightStart || animation.frameIndex > (rightStart + animation.framesCount / 2);
if (stand == STAND_UNDERWATER) {
if (collision.side == Collision::TOP)
@@ -1963,7 +1964,7 @@ struct Lara : Character {
if (stand == STAND_AIR && collision.side == Collision::TOP && velocity.y < 0.0f)
velocity.y = 30.0f;
if (collision.side == Collision::FRONT) {
if (collision.side == Collision::FRONT) {
int floor = collision.info[Collision::FRONT].floor;
// hit the wall
@@ -1997,7 +1998,7 @@ struct Lara : Character {
pos.y = opos.y;
break;
default : ;// no smash animation
}
}
} else {
if (stand == STAND_GROUND) {
int floor = collision.info[Collision::NONE].floor;

View File

@@ -330,7 +330,7 @@ struct Level : IGame {
}
void initReflections() {
Core::resetStates();
Core::beginFrame();
for (int i = 0; i < level.entitiesBaseCount; i++) {
TR::Entity &e = level.entities[i];
if (e.type == TR::Entity::CRYSTAL) {
@@ -338,6 +338,7 @@ struct Level : IGame {
renderEnvironment(c->getRoomIndex(), c->pos - vec3(0, 512, 0), &c->environment);
}
}
Core::endFrame();
}
void setRoomParams(int roomIndex, Shader::Type type, float diffuse, float ambient, float specular, float alpha, bool alphaTest = false) {
@@ -523,7 +524,7 @@ struct Level : IGame {
vec3 pos = controller->getPos();
if (Core::settings.ambient) {
AmbientCache::Cube cube;
if (Core::frameIndex != controller->frameIndex) {
if (Core::stats.frame != controller->frameIndex) {
ambientCache->getAmbient(entity.room, pos, cube);
if (cube.status == AmbientCache::Cube::READY)
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller
@@ -642,6 +643,29 @@ struct Level : IGame {
Core::mProj = mat4(90, 1.0f, camera->znear, camera->zfar);
}
mat4 calcCromMatrix(const mat4 &lightViewProj, const Box *boxes, int count) {
mat4 cameraViewProjInv = (mat4(camera->fov, float(Core::width) / Core::height, 512.0f, 4096.0f) * camera->mViewInv.inverse()).inverse();
Box frustumBox = Box(vec3(-1.0f), vec3(1.0f)) * cameraViewProjInv;
Box casterBox(vec3(+INF), vec3(-INF));
for (int i = 0; i < count; i++)
casterBox += boxes[i] * lightViewProj;
casterBox -= frustumBox * lightViewProj;
vec3 scale = vec3(2.0f, 2.0f, 1.0f) / casterBox.size();
vec3 center = casterBox.center();
vec3 offset = vec3(center.x, center.y, casterBox.min.z) * scale;
return mat4(scale.x, 0.0f, 0.0f, 0.0f,
0.0f, scale.y, 0.0f, 0.0f,
0.0f, 0.0f, scale.z, 0.0f,
-offset.x, -offset.y, -offset.z, 1.0f);
}
bool setupLightCamera() {
vec3 pos = lara->getPos();
@@ -654,12 +678,32 @@ struct Level : IGame {
vec3 shadowLightPos = vec3(float(light.x), float(light.y), float(light.z));
Core::mViewInv = mat4(shadowLightPos, pos - vec3(0, 256, 0), vec3(0, -1, 0));
Core::mView = Core::mViewInv.inverse();
Core::mProj = mat4(120, 1.0f, camera->znear, camera->zfar);
Core::mProj = mat4(120.0f, 1.0f, camera->znear, camera->zfar);
mat4 bias;
bias.identity();
bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f;
Core::mLightProj = bias * Core::mProj * Core::mView;
/*
Box boxes[32];
int bCount = 0;
float rq = light.radius * light.radius;
for (int i = 0; i < level.entitiesCount; i++) {
TR::Entity &e = level.entities[i];
Controller *controller = (Controller*)e.controller;
if (controller && TR::castShadow(e.type) && rq > (shadowLightPos - controller->pos).length2())
boxes[bCount++] = controller->getBoundingBox();
}
*/
/*
vec3 shadowBox(1024.0f, 0.0f, 1024.0f);
boxes[0] = lara->getBoundingBox();
boxes[0] += Box(lara->pos - shadowBox, lara->pos + shadowBox);
bCount++;
Core::mProj = calcCromMatrix(Core::mProj * Core::mView, &boxes[0], bCount) * Core::mProj;
*/
Core::mLightProj = bias * (Core::mProj * Core::mView);
return true;
}
@@ -672,7 +716,8 @@ struct Level : IGame {
bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false;
if (colorShadow)
Core::setClearColor(vec4(1.0f, 1.0f, 1.0f, 1.0f));
Core::setTarget(shadow, true);
Core::setTarget(shadow);
Core::clear(true, true);
Core::setCulling(cfBack);
renderScene(roomIndex);
Core::invalidateTarget(!colorShadow, colorShadow);
@@ -686,7 +731,6 @@ struct Level : IGame {
params->clipHeight = NO_CLIP_PLANE;
params->clipSign = 1.0f;
params->waterHeight = params->clipHeight;
Core::resetStates();
if (ambientCache)
ambientCache->precessQueue();
@@ -695,7 +739,8 @@ struct Level : IGame {
if (shadow)
renderShadows(lara->getRoomIndex());
Core::setTarget(NULL, true);
Core::setTarget(NULL);
Core::clear(true, true);
Core::setViewport(0, 0, Core::width, Core::height);
if (waterCache)
@@ -789,10 +834,10 @@ struct Level : IGame {
glLoadIdentity();
glOrtho(0, Core::width, 0, Core::height, 0, 1);
if (waterCache->count)
waterCache->refract->bind(sDiffuse);
else
atlas->bind(sDiffuse);
// if (waterCache->count)
// waterCache->refract->bind(sDiffuse);
// else
shadow->bind(sDiffuse);
glEnable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);

View File

@@ -33,7 +33,7 @@ void sndInit() {
.rate = 44100,
.channels = 2
};
static const pa_buffer_attr attr = {
.maxlength = SND_DATA_SIZE * 2,
.tlength = 0xFFFFFFFF,
@@ -44,20 +44,20 @@ void sndInit() {
pthread_mutex_init(&sndMutex, NULL);
int error;
int error;
if (!(sndOut = pa_simple_new(NULL, WND_TITLE, PA_STREAM_PLAYBACK, NULL, "game", &spec, NULL, &attr, &error))) {
LOG("pa_simple_new() failed: %s\n", pa_strerror(error));
sndData = NULL;
return;
}
sndData = new Sound::Frame[SND_DATA_SIZE / SND_FRAME_SIZE];
pthread_create(&sndThread, NULL, sndFill, NULL);
sndData = new Sound::Frame[SND_DATA_SIZE / SND_FRAME_SIZE];
pthread_create(&sndThread, NULL, sndFill, NULL);
}
void sndFree() {
if (sndOut) {
pthread_cancel(sndThread);
pthread_cancel(sndThread);
pthread_mutex_lock(&sndMutex);
// pa_simple_flush(sndOut, NULL);
// pa_simple_free(sndOut);
@@ -102,7 +102,7 @@ void WndProc(const XEvent &e) {
Core::width = e.xconfigure.width;
Core::height = e.xconfigure.height;
break;
case KeyPress :
case KeyPress :
case KeyRelease :
if (e.type == KeyPress && (e.xkey.state & Mod1Mask) && e.xkey.keycode == 36) {
// TODO: windowed <-> fullscreen switch
@@ -120,10 +120,15 @@ void WndProc(const XEvent &e) {
case MotionNotify :
Input::setPos(ikMouseL, vec2((float)e.xmotion.x, (float)e.xmotion.y));
break;
}
}
}
char Stream::cacheDir[255];
char Stream::contentDir[255];
int main() {
Stream::contentDir[0] = Stream::cacheDir[0] = 0;
static int XGLAttr[] = {
GLX_RGBA,
GLX_DOUBLEBUFFER,
@@ -142,8 +147,8 @@ int main() {
ButtonMotionMask | PointerMotionMask;
Window wnd = XCreateWindow(dpy, RootWindow(dpy, vis->screen),
0, 0, 1280, 720, 0,
vis->depth, InputOutput, vis->visual,
0, 0, 1280, 720, 0,
vis->depth, InputOutput, vis->visual,
CWColormap | CWBorderPixel | CWEventMask, &attr);
XStoreName(dpy, wnd, WND_TITLE);
@@ -156,9 +161,9 @@ int main() {
sndInit();
Game::init();
int lastTime = getTime(), fpsTime = lastTime + 1000, fps = 0;
int lastTime = getTime();
while (1) {
if (XPending(dpy)) {
XEvent event;
@@ -181,20 +186,11 @@ int main() {
pthread_mutex_unlock(&sndMutex);
lastTime = time;
Core::stats.dips = 0;
Core::stats.tris = 0;
Game::render();
glXSwapBuffers(dpy, wnd);
if (fpsTime < getTime()) {
LOG("FPS: %d DIP: %d TRI: %d\n", fps, Core::stats.dips, Core::stats.tris);
fps = 0;
fpsTime = getTime() + 1000;
} else
fps++;
}
};
sndFree();
Game::free();

View File

@@ -3,7 +3,7 @@
#include "game.h"
int lastTime, fpsTime, fps;
int lastTime;
EGLDisplay display;
EGLSurface surface;
EGLContext context;
@@ -23,7 +23,7 @@ extern "C" {
}
InputKey joyToInputKey(int code) {
static const int codes[] = { 0, 1, 2, 3, 4, 5, 10, 11, 8, 9, 6, 7 };
static const int codes[] = { 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 6, 7 };
for (int i = 0; i < sizeof(codes) / sizeof(codes[0]); i++)
if (codes[i] == code)
@@ -63,9 +63,13 @@ void joyUpdate() {
int count = emscripten_get_num_gamepads();
if (count <= 0)
return;
EmscriptenGamepadEvent state;
if (emscripten_get_gamepad_status(0, &state) != EMSCRIPTEN_RESULT_SUCCESS)
for (int i = 0; i < count; i++)
if (emscripten_get_gamepad_status(i, &state) == EMSCRIPTEN_RESULT_SUCCESS && state.numButtons >= 12)
break;
if (state.numButtons < 12)
return;
for (int i = 0; i < max(state.numButtons, 12); i++) {
@@ -101,17 +105,8 @@ void main_loop() {
}
lastTime = time;
Core::stats.dips = 0;
Core::stats.tris = 0;
Game::render();
eglSwapBuffers(display, surface);
if (fpsTime < getTime()) {
LOG("FPS: %d DIP: %d TRI: %d\n", fps, Core::stats.dips, Core::stats.tris);
fps = 0;
fpsTime = getTime() + 1000;
} else
fps++;
}
bool initGL() {
@@ -291,8 +286,6 @@ int main() {
resize();
lastTime = getTime();
fpsTime = lastTime + 1000;
fps = 0;
emscripten_set_main_loop(main_loop, 0, true);

View File

@@ -13,15 +13,15 @@
#include "game.h"
DWORD getTime() {
int getTime() {
#ifdef DEBUG
LARGE_INTEGER Freq, Count;
QueryPerformanceFrequency(&Freq);
QueryPerformanceCounter(&Count);
return (DWORD)(Count.QuadPart * 1000L / Freq.QuadPart);
return int(Count.QuadPart * 1000L / Freq.QuadPart);
#else
timeBeginPeriod(0);
return timeGetTime();
return int(timeGetTime());
#endif
}
@@ -232,8 +232,8 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
break;
case WM_KEYDOWN :
case WM_KEYUP :
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_SYSKEYDOWN :
case WM_SYSKEYUP :
if (msg == WM_SYSKEYDOWN && wParam == VK_RETURN) { // switch to fullscreen or window
static WINDOWPLACEMENT pLast;
DWORD style = GetWindowLong(hWnd, GWL_STYLE);
@@ -262,6 +262,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
case WM_MBUTTONDOWN :
case WM_MBUTTONUP :
case WM_MBUTTONDBLCLK : {
if ((GetMessageExtraInfo() & 0xFFFFFF00) == 0xFF515700) break;
InputKey key = mouseToInputKey(msg);
Input::setPos(key, vec2((float)(short)LOWORD(lParam), (float)(short)HIWORD(lParam)));
bool down = msg != WM_LBUTTONUP && msg != WM_RBUTTONUP && msg != WM_MBUTTONUP;
@@ -273,6 +274,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
break;
}
case WM_MOUSEMOVE :
if ((GetMessageExtraInfo() & 0xFFFFFF00) == 0xFF515700) break;
Input::setPos(ikMouseL, vec2((float)(short)LOWORD(lParam), (float)(short)HIWORD(lParam)));
break;
// joystick
@@ -355,7 +357,7 @@ int main(int argc, char** argv) {
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc);
ShowWindow(hWnd, SW_SHOWDEFAULT);
DWORD lastTime = getTime(), fpsTime = lastTime + 1000, fps = 0;
DWORD lastTime = getTime();
MSG msg;
do {
@@ -379,20 +381,11 @@ int main(int argc, char** argv) {
LeaveCriticalSection(&sndCS);
lastTime = time;
Core::stats.dips = 0;
Core::stats.tris = 0;
Game::render();
SwapBuffers(hDC);
#ifdef _DEBUG
Sleep(20);
#endif
if (fpsTime < getTime()) {
LOG("FPS: %d DIP: %d TRI: %d\n", fps, Core::stats.dips, Core::stats.tris);
fps = 0;
fpsTime = getTime() + 1000;
} else
fps++;
}
} while (msg.message != WM_QUIT);

View File

@@ -204,26 +204,28 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
}
#endif
#define SHADOW_TEXEL (1.5 / 1024.0)
float getShadow(vec4 lightProj) {
vec3 p = lightProj.xyz / lightProj.w;
float rShadow = 0.0;
rShadow += SHADOW(p + (vec3(-0.94201624, -0.39906216, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.94558609, -0.76890725, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.09418410, -0.92938870, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.34495938, 0.29387760, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.91588581, 0.45771432, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.81544232, -0.87912464, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.38277543, 0.27676845, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.97484398, 0.75648379, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.44323325, -0.97511554, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.53742981, -0.47373420, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.26496911, -0.41893023, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.79197514, 0.19090188, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.24188840, 0.99706507, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.81409955, 0.91437590, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.19984126, 0.78641367, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.14383161, -0.14100790, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.94201624, -0.39906216, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3( 0.94558609, -0.76890725, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3(-0.09418410, -0.92938870, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3( 0.34495938, 0.29387760, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3(-0.91588581, 0.45771432, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3(-0.81544232, -0.87912464, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3(-0.38277543, 0.27676845, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3( 0.97484398, 0.75648379, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3( 0.44323325, -0.97511554, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3( 0.53742981, -0.47373420, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3(-0.26496911, -0.41893023, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3( 0.79197514, 0.19090188, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3(-0.24188840, 0.99706507, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3(-0.81409955, 0.91437590, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3( 0.19984126, 0.78641367, 0.0) * SHADOW_TEXEL));
rShadow += SHADOW(p + (vec3( 0.14383161, -0.14100790, 0.0) * SHADOW_TEXEL));
rShadow /= 16.0;

View File

@@ -143,16 +143,20 @@ struct vec2 {
vec2& operator += (const vec2 &v) { x += v.x; y += v.y; return *this; }
vec2& operator -= (const vec2 &v) { x -= v.x; y -= v.y; return *this; }
vec2& operator *= (const vec2 &v) { x *= v.x; y *= v.y; return *this; }
vec2& operator /= (const vec2 &v) { x /= v.x; y /= v.y; return *this; }
vec2& operator += (float s) { x += s; y += s; return *this; }
vec2& operator -= (float s) { x -= s; y -= s; return *this; }
vec2& operator *= (float s) { x *= s; y *= s; return *this; }
vec2& operator /= (float s) { x /= s; y /= s; return *this; }
vec2 operator + (const vec2 &v) const { return vec2(x + v.x, y + v.y); }
vec2 operator - (const vec2 &v) const { return vec2(x - v.x, y - v.y); }
vec2 operator * (const vec2 &v) const { return vec2(x * v.x, y * v.y); }
vec2 operator / (const vec2 &v) const { return vec2(x / v.x, y / v.y); }
vec2 operator + (float s) const { return vec2(x + s, y + s ); }
vec2 operator - (float s) const { return vec2(x - s, y - s ); }
vec2 operator * (float s) const { return vec2(x * s, y * s ); }
vec2 operator / (float s) const { return vec2(x / s, y / s ); }
float dot(const vec2 &v) const { return x * v.x + y * v.y; }
float cross(const vec2 &v) const { return x * v.y - y * v.x; }
@@ -164,7 +168,11 @@ struct vec2 {
};
struct vec3 {
float x, y, z;
union {
struct { vec2 xy; };
struct { float x, y, z; };
};
vec3() {}
vec3(float s) : x(s), y(s), z(s) {}
vec3(float x, float y, float z) : x(x), y(y), z(z) {}
@@ -182,16 +190,20 @@ struct vec3 {
vec3& operator += (const vec3 &v) { x += v.x; y += v.y; z += v.z; return *this; }
vec3& operator -= (const vec3 &v) { x -= v.x; y -= v.y; z -= v.z; return *this; }
vec3& operator *= (const vec3 &v) { x *= v.x; y *= v.y; z *= v.z; return *this; }
vec3& operator /= (const vec3 &v) { x /= v.x; y /= v.y; z /= v.z; return *this; }
vec3& operator += (float s) { x += s; y += s; z += s; return *this; }
vec3& operator -= (float s) { x -= s; y -= s; z -= s; return *this; }
vec3& operator *= (float s) { x *= s; y *= s; z *= s; return *this; }
vec3& operator /= (float s) { x /= s; y /= s; z /= s; return *this; }
vec3 operator + (const vec3 &v) const { return vec3(x + v.x, y + v.y, z + v.z); }
vec3 operator - (const vec3 &v) const { return vec3(x - v.x, y - v.y, z - v.z); }
vec3 operator * (const vec3 &v) const { return vec3(x * v.x, y * v.y, z * v.z); }
vec3 operator / (const vec3 &v) const { return vec3(x / v.x, y / v.y, z / v.z); }
vec3 operator + (float s) const { return vec3(x + s, y + s, z + s); }
vec3 operator - (float s) const { return vec3(x - s, y - s, z - s); }
vec3 operator * (float s) const { return vec3(x * s, y * s, z * s); }
vec3 operator / (float s) const { return vec3(x / s, y / s, z / s); }
float dot(const vec3 &v) const { return x * v.x + y * v.y + z * v.z; }
vec3 cross(const vec3 &v) const { return vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); }
@@ -219,6 +231,7 @@ struct vec3 {
struct vec4 {
union {
struct { vec2 xy; };
struct { vec3 xyz; };
struct { float x, y, z, w; };
};
@@ -356,6 +369,15 @@ struct mat4 {
mat4() {}
mat4(float e00, float e10, float e20, float e30,
float e01, float e11, float e21, float e31,
float e02, float e12, float e22, float e32,
float e03, float e13, float e23, float e33) :
e00(e00), e10(e10), e20(e20), e30(e30),
e01(e01), e11(e11), e21(e21), e31(e31),
e02(e02), e12(e12), e22(e22), e32(e32),
e03(e03), e13(e13), e23(e23), e33(e33) {}
mat4(const quat &rot, const vec3 &pos) {
setRot(rot);
setPos(pos);
@@ -683,6 +705,60 @@ struct Box {
Box() {}
Box(const vec3 &min, const vec3 &max) : min(min), max(max) {}
vec3 operator [] (int index) const {
ASSERT(index >= 0 && index <= 7);
switch (index) {
case 0 : return min;
case 1 : return max;
case 2 : return vec3(min.x, max.y, max.z);
case 3 : return vec3(max.x, min.y, max.z);
case 4 : return vec3(min.x, min.y, max.z);
case 5 : return vec3(max.x, max.y, min.z);
case 6 : return vec3(min.x, max.y, min.z);
case 7 : return vec3(max.x, min.y, min.z);
}
return min;
}
Box& operator += (const Box &box) {
min.x = ::min(min.x, box.min.x);
min.y = ::min(min.y, box.min.y);
min.z = ::min(min.z, box.min.z);
max.x = ::max(max.x, box.max.x);
max.y = ::max(max.y, box.max.y);
max.z = ::max(max.z, box.max.z);
return *this;
}
Box& operator += (const vec3 &v) {
min.x = ::min(min.x, v.x);
min.y = ::min(min.y, v.y);
min.z = ::min(min.z, v.z);
max.x = ::max(max.x, v.x);
max.y = ::max(max.y, v.y);
max.z = ::max(max.z, v.z);
return *this;
}
Box& operator -= (const Box &box) {
min.x = ::max(min.x, box.min.x);
min.y = ::max(min.y, box.min.y);
min.z = ::max(min.z, box.min.z);
max.x = ::min(max.x, box.max.x);
max.y = ::min(max.y, box.max.y);
max.z = ::min(max.z, box.max.z);
return *this;
}
Box operator * (const mat4 &m) const {
Box res(vec3(+INF), vec3(-INF));
for (int i = 0; i < 8; i++) {
vec4 v = m * vec4((*this)[i], 1.0f);
res += v.xyz /= v.w;
}
return res;
}
vec3 center() const {
return (min + max) * 0.5f;
}