1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-18 02:41:29 +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 {
@@ -361,8 +377,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);
data = 0xFFFFFFFF;
@@ -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

@@ -1641,16 +1641,17 @@ struct Lara : Character {
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)
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 (!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;

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

@@ -123,7 +123,12 @@ void WndProc(const XEvent &e) {
}
}
char Stream::cacheDir[255];
char Stream::contentDir[255];
int main() {
Stream::contentDir[0] = Stream::cacheDir[0] = 0;
static int XGLAttr[] = {
GLX_RGBA,
GLX_DOUBLEBUFFER,
@@ -157,7 +162,7 @@ int main() {
sndInit();
Game::init();
int lastTime = getTime(), fpsTime = lastTime + 1000, fps = 0;
int lastTime = getTime();
while (1) {
if (XPending(dpy)) {
@@ -181,17 +186,8 @@ 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++;
}
};

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)
@@ -65,7 +65,11 @@ void joyUpdate() {
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;
}