Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "Camera.h"
- #include "GameHeader.h"
- #include <GL/glew.h>
- #include <cmath>
- Camera::Camera() :
- width(256),
- height(256) {
- worldView.MakeIdentity();
- projection.MakeIdentity();
- }
- void Camera::SetSize(int w, int h, float n, float f) {
- width = w;
- height = h;
- near = n;
- far = f;
- const float e = 1.0f / std::tan(GH_FOV * GH_PI / 360.0f);
- const float a = float(height) / float(width);
- const float d = near - far;
- projection.m[0] = e * a;
- projection.m[1] = 0.0f;
- projection.m[2] = 0.0f;
- projection.m[3] = 0.0f;
- projection.m[4] = 0.0f;
- projection.m[5] = e;
- projection.m[6] = 0.0f;
- projection.m[7] = 0.0f;
- projection.m[8] = 0.0f;
- projection.m[9] = 0.0f;
- projection.m[10] = (near + far) / d;
- projection.m[11] = (2 * near * far) / d;
- projection.m[12] = 0.0f;
- projection.m[13] = 0.0f;
- projection.m[14] = -1.0f;
- projection.m[15] = 0.0f;
- }
- void Camera::SetPositionOrientation(const Vector3& pos, float rotX, float rotY) {
- worldView = Matrix4::RotX(rotX) * Matrix4::RotY(rotY) * Matrix4::Trans(-pos);
- }
- Matrix4 Camera::InverseProjection() const {
- Matrix4 invProjection = Matrix4::Zero();
- const float a = projection.m[0];
- const float b = projection.m[5];
- const float c = projection.m[10];
- const float d = projection.m[11];
- const float e = projection.m[14];
- invProjection.m[0] = 1.0f / a;
- invProjection.m[5] = 1.0f / b;
- invProjection.m[11] = 1.0f / e;
- invProjection.m[14] = 1.0f / d;
- invProjection.m[15] = -c / (d * e);
- return invProjection;
- }
- Matrix4 Camera::Matrix() const {
- return projection * worldView;
- }
- void Camera::UseViewport() const {
- glViewport(0, 0, width, height);
- }
- void Camera::ClipOblique(const Vector3& pos, const Vector3& normal) {
- const Vector3 cpos = (worldView * Vector4(pos, 1)).XYZ();
- const Vector3 cnormal = (worldView * Vector4(normal, 0)).XYZ();
- const Vector4 cplane(cnormal.x, cnormal.y, cnormal.z, -cpos.Dot(cnormal));
- const Vector4 q = projection.Inverse() * Vector4(
- (cplane.x < 0.0f ? 1.0f : -1.0f),
- (cplane.y < 0.0f ? 1.0f : -1.0f),
- 1.0f,
- 1.0f
- );
- const Vector4 c = cplane * (2.0f / cplane.Dot(q));
- projection.m[8] = c.x - projection.m[12];
- projection.m[9] = c.y - projection.m[13];
- projection.m[10] = c.z - projection.m[14];
- projection.m[11] = c.w - projection.m[15];
- }
- #pragma once
- #include "Vector.h"
- class Camera {
- public:
- Camera();
- Matrix4 InverseProjection() const;
- Matrix4 Matrix() const;
- void SetSize(int w, int h, float n, float f);
- void SetPositionOrientation(const Vector3& pos, float rotX, float rotY);
- void UseViewport() const;
- void ClipOblique(const Vector3& pos, const Vector3& normal);
- Matrix4 projection;
- Matrix4 worldView;
- int width;
- int height;
- float near;
- float far;
- };
- #include "Collider.h"
- #include "GameHeader.h"
- #include "GL/glew.h"
- #include <cassert>
- #include <iostream>
- Collider::Collider(const Vector3& a, const Vector3& b, const Vector3& c) {
- const Vector3 ab = b - a;
- const Vector3 bc = c - b;
- const Vector3 ca = a - c;
- const float magAB = ab.MagSq();
- const float magBC = bc.MagSq();
- const float magCA = ca.MagSq();
- if (magAB >= magBC && magAB >= magCA) {
- CreateSorted(bc*0.5f, (a + b)*0.5f, ca*0.5f);
- } else if (magBC >= magAB && magBC >= magCA) {
- CreateSorted(ca*0.5f, (b + c)*0.5f, ab*0.5f);
- } else {
- CreateSorted(ab*0.5f, (c + a)*0.5f, bc*0.5f);
- }
- }
- bool Collider::Collide(const Matrix4& localToUnit, Vector3& delta) const {
- //Get world delta
- const Matrix4 local = localToUnit * mat;
- const Vector3 v = -local.Translation();
- //Get axes
- const Vector3 x = local.XAxis();
- const Vector3 y = local.YAxis();
- //Find closest point
- const float px = GH_CLAMP(v.Dot(x) / x.MagSq(), -1.0f, 1.0f);
- const float py = GH_CLAMP(v.Dot(y) / y.MagSq(), -1.0f, 1.0f);
- const Vector3 closest = x*px + y*py;
- //Calculate distance to closest point
- delta = v - closest;
- if (delta.MagSq() >= 1.0f) {
- return false;
- } else {
- delta = delta.Normalized() - delta;
- return true;
- }
- }
- void Collider::DebugDraw(const Camera& cam, const Matrix4& objMat) {
- glDepthFunc(GL_ALWAYS);
- glUseProgram(0);
- glBegin(GL_LINE_LOOP);
- glColor3f(0.0f, 1.0f, 0.0f);
- const Matrix4 m = cam.Matrix() * objMat * mat;
- Vector4 v;
- v = m * Vector4(1, 1, 0, 1);
- glVertex4f(v.x, v.y, v.z, v.w);
- v = m * Vector4(1, -1, 0, 1);
- glVertex4f(v.x, v.y, v.z, v.w);
- v = m * Vector4(-1, -1, 0, 1);
- glVertex4f(v.x, v.y, v.z, v.w);
- v = m * Vector4(-1, 1, 0, 1);
- glVertex4f(v.x, v.y, v.z, v.w);
- glEnd();
- glDepthFunc(GL_LESS);
- }
- void Collider::CreateSorted(const Vector3& da, const Vector3& c, const Vector3& db) {
- assert(std::abs(da.Dot(db)) / (da.Mag() * db.Mag()) < 0.001f);
- mat.MakeIdentity();
- mat.SetTranslation(c);
- mat.SetXAxis(da);
- mat.SetYAxis(db);
- }
- #pragma once
- #include "Vector.h"
- #include "Camera.h"
- class Collider {
- public:
- Collider(const Vector3& a, const Vector3& b, const Vector3& c);
- bool Collide(const Matrix4& localToWorld, Vector3& delta) const;
- void DebugDraw(const Camera& cam, const Matrix4& objMat);
- private:
- void CreateSorted(const Vector3& da, const Vector3& c, const Vector3& db);
- Matrix4 mat;
- };
- #include "Engine.h"
- #include "Physical.h"
- #include "Level1.h"
- #include "Level2.h"
- #include "Level3.h"
- #include "Level4.h"
- #include "Level5.h"
- #include "Level6.h"
- #include <GL/wglew.h>
- #include <cmath>
- #include <iostream>
- #include <algorithm>
- Engine* GH_ENGINE = nullptr;
- Player* GH_PLAYER = nullptr;
- const Input* GH_INPUT = nullptr;
- int GH_REC_LEVEL = 0;
- int64_t GH_FRAME = 0;
- LRESULT WINAPI StaticWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
- Engine* eng = (Engine*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
- if (eng) {
- return eng->WindowProc(hWnd, uMsg, wParam, lParam);
- }
- return DefWindowProc(hWnd, uMsg, wParam, lParam);
- }
- Engine::Engine() : hWnd(NULL), hDC(NULL), hRC(NULL) {
- GH_ENGINE = this;
- GH_INPUT = &input;
- isFullscreen = false;
- SetProcessDPIAware();
- CreateGLWindow();
- InitGLObjects();
- SetupInputs();
- player.reset(new Player);
- GH_PLAYER = player.get();
- vScenes.push_back(std::shared_ptr<Scene>(new Level1));
- vScenes.push_back(std::shared_ptr<Scene>(new Level2(3)));
- vScenes.push_back(std::shared_ptr<Scene>(new Level2(6)));
- vScenes.push_back(std::shared_ptr<Scene>(new Level3));
- vScenes.push_back(std::shared_ptr<Scene>(new Level4));
- vScenes.push_back(std::shared_ptr<Scene>(new Level5));
- vScenes.push_back(std::shared_ptr<Scene>(new Level6));
- LoadScene(0);
- sky.reset(new Sky);
- }
- Engine::~Engine() {
- ClipCursor(NULL);
- wglMakeCurrent(NULL, NULL);
- ReleaseDC(hWnd, hDC);
- wglDeleteContext(hRC);
- DestroyWindow(hWnd);
- }
- int Engine::Run() {
- if (!hWnd || !hDC || !hRC) {
- return 1;
- }
- //Recieve events from this window
- SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)this);
- //Setup the timer
- const int64_t ticks_per_step = timer.SecondsToTicks(GH_DT);
- int64_t cur_ticks = timer.GetTicks();
- GH_FRAME = 0;
- //Game loop
- MSG msg;
- while (true) {
- if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
- //Handle windows messages
- if (msg.message == WM_QUIT) {
- break;
- } else {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- } else {
- //Confine the cursor
- ConfineCursor();
- if (input.key_press['1']) {
- LoadScene(0);
- } else if (input.key_press['2']) {
- LoadScene(1);
- } else if (input.key_press['3']) {
- LoadScene(2);
- } else if (input.key_press['4']) {
- LoadScene(3);
- } else if (input.key_press['5']) {
- LoadScene(4);
- } else if (input.key_press['6']) {
- LoadScene(5);
- } else if (input.key_press['7']) {
- LoadScene(6);
- }
- //Used fixed time steps for updates
- const int64_t new_ticks = timer.GetTicks();
- for (int i = 0; cur_ticks < new_ticks && i < GH_MAX_STEPS; ++i) {
- Update();
- cur_ticks += ticks_per_step;
- GH_FRAME += 1;
- input.EndFrame();
- }
- cur_ticks = (cur_ticks < new_ticks ? new_ticks: cur_ticks);
- //Setup camera for rendering
- const float n = GH_CLAMP(NearestPortalDist() * 0.5f, GH_NEAR_MIN, GH_NEAR_MAX);
- main_cam.worldView = player->WorldToCam();
- main_cam.SetSize(iWidth, iHeight, n, GH_FAR);
- main_cam.UseViewport();
- //Render scene
- GH_REC_LEVEL = GH_MAX_RECURSION;
- Render(main_cam, 0, nullptr);
- SwapBuffers(hDC);
- }
- }
- DestroyGLObjects();
- return 0;
- }
- void Engine::LoadScene(int ix) {
- //Clear out old scene
- if (curScene) { curScene->Unload(); }
- vObjects.clear();
- vPortals.clear();
- player->Reset();
- //Create new scene
- curScene = vScenes[ix];
- curScene->Load(vObjects, vPortals, *player);
- vObjects.push_back(player);
- }
- void Engine::Update() {
- //Update
- for (size_t i = 0; i < vObjects.size(); ++i) {
- assert(vObjects[i].get());
- vObjects[i]->Update();
- }
- //Collisions
- //For each physics object
- for (size_t i = 0; i < vObjects.size(); ++i) {
- Physical* physical = vObjects[i]->AsPhysical();
- if (!physical) { continue; }
- Matrix4 worldToLocal = physical->WorldToLocal();
- //For each object to collide with
- for (size_t j = 0; j < vObjects.size(); ++j) {
- if (i == j) { continue; }
- Object& obj = *vObjects[j];
- if (!obj.mesh) { continue; }
- //For each hit sphere
- for (size_t s = 0; s < physical->hitSpheres.size(); ++s) {
- //Brings point from collider's local coordinates to hits's local coordinates.
- const Sphere& sphere = physical->hitSpheres[s];
- Matrix4 worldToUnit = sphere.LocalToUnit() * worldToLocal;
- Matrix4 localToUnit = worldToUnit * obj.LocalToWorld();
- Matrix4 unitToWorld = worldToUnit.Inverse();
- //For each collider
- for (size_t c = 0; c < obj.mesh->colliders.size(); ++c) {
- Vector3 push;
- const Collider& collider = obj.mesh->colliders[c];
- if (collider.Collide(localToUnit, push)) {
- //If push is too small, just ignore
- push = unitToWorld.MulDirection(push);
- vObjects[j]->OnHit(*physical, push);
- physical->OnCollide(*vObjects[j], push);
- worldToLocal = physical->WorldToLocal();
- worldToUnit = sphere.LocalToUnit() * worldToLocal;
- localToUnit = worldToUnit * obj.LocalToWorld();
- unitToWorld = worldToUnit.Inverse();
- }
- }
- }
- }
- }
- //Portals
- for (size_t i = 0; i < vObjects.size(); ++i) {
- Physical* physical = vObjects[i]->AsPhysical();
- if (physical) {
- for (size_t j = 0; j < vPortals.size(); ++j) {
- if (physical->TryPortal(*vPortals[j])) {
- break;
- }
- }
- }
- }
- }
- void Engine::Render(const Camera& cam, GLuint curFBO, const Portal* skipPortal) {
- //Clear buffers
- if (GH_USE_SKY) {
- glClear(GL_DEPTH_BUFFER_BIT);
- sky->Draw(cam);
- } else {
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
- //Create queries (if applicable)
- GLuint queries[GH_MAX_PORTALS];
- GLuint drawTest[GH_MAX_PORTALS];
- assert(vPortals.size() <= GH_MAX_PORTALS);
- if (occlusionCullingSupported) {
- glGenQueriesARB((GLsizei)vPortals.size(), queries);
- }
- //Draw scene
- for (size_t i = 0; i < vObjects.size(); ++i) {
- vObjects[i]->Draw(cam, curFBO);
- }
- //Draw portals if possible
- if (GH_REC_LEVEL > 0) {
- //Draw portals
- GH_REC_LEVEL -= 1;
- if (occlusionCullingSupported && GH_REC_LEVEL > 0) {
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- glDepthMask(GL_FALSE);
- for (size_t i = 0; i < vPortals.size(); ++i) {
- if (vPortals[i].get() != skipPortal) {
- glBeginQueryARB(GL_SAMPLES_PASSED_ARB, queries[i]);
- vPortals[i]->DrawPink(cam);
- glEndQueryARB(GL_SAMPLES_PASSED_ARB);
- }
- }
- for (size_t i = 0; i < vPortals.size(); ++i) {
- if (vPortals[i].get() != skipPortal) {
- glGetQueryObjectuivARB(queries[i], GL_QUERY_RESULT_ARB, &drawTest[i]);
- }
- };
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glDepthMask(GL_TRUE);
- glDeleteQueriesARB((GLsizei)vPortals.size(), queries);
- }
- for (size_t i = 0; i < vPortals.size(); ++i) {
- if (vPortals[i].get() != skipPortal) {
- if (occlusionCullingSupported && (GH_REC_LEVEL > 0) && (drawTest[i] == 0)) {
- continue;
- } else {
- vPortals[i]->Draw(cam, curFBO);
- }
- }
- }
- GH_REC_LEVEL += 1;
- }
- #if 0
- //Debug draw colliders
- for (size_t i = 0; i < vObjects.size(); ++i) {
- vObjects[i]->DebugDraw(cam);
- }
- #endif
- }
- LRESULT Engine::WindowProc(HWND hCurWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
- static PAINTSTRUCT ps;
- static BYTE lpb[256];
- static UINT dwSize = sizeof(lpb);
- switch (uMsg) {
- case WM_SYSCOMMAND:
- if (wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER) {
- return 0;
- }
- break;
- case WM_PAINT:
- BeginPaint(hCurWnd, &ps);
- EndPaint(hCurWnd, &ps);
- return 0;
- case WM_SIZE:
- iWidth = LOWORD(lParam);
- iHeight = HIWORD(lParam);
- PostMessage(hCurWnd, WM_PAINT, 0, 0);
- return 0;
- case WM_KEYDOWN:
- //Ignore repeat keys
- if (lParam & 0x40000000) { return 0; }
- input.key[wParam & 0xFF] = true;
- input.key_press[wParam & 0xFF] = true;
- if (wParam == VK_ESCAPE) {
- PostQuitMessage(0);
- }
- return 0;
- case WM_SYSKEYDOWN:
- if (wParam == VK_RETURN) {
- ToggleFullscreen();
- return 0;
- }
- break;
- case WM_KEYUP:
- input.key[wParam & 0xFF] = false;
- return 0;
- case WM_INPUT:
- dwSize = sizeof(lpb);
- GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
- input.UpdateRaw((const RAWINPUT*)lpb);
- break;
- case WM_CLOSE:
- PostQuitMessage(0);
- return 0;
- }
- return DefWindowProc(hCurWnd, uMsg, wParam, lParam);
- }
- void Engine::CreateGLWindow() {
- WNDCLASSEX wc;
- hInstance = GetModuleHandle(NULL);
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.style = CS_OWNDC;
- wc.lpfnWndProc = (WNDPROC)StaticWindowProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = hInstance;
- wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = NULL;
- wc.lpszMenuName = NULL;
- wc.lpszClassName = GH_CLASS;
- wc.hIconSm = NULL;
- if (!RegisterClassEx(&wc)) {
- MessageBoxEx(NULL, "RegisterClass() failed: Cannot register window class.", "Error", MB_OK, 0);
- return;
- }
- //Always start in windowed mode
- iWidth = GH_SCREEN_WIDTH;
- iHeight = GH_SCREEN_HEIGHT;
- //Create the window
- hWnd = CreateWindowEx(
- WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
- GH_CLASS,
- GH_TITLE,
- WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
- GH_SCREEN_X,
- GH_SCREEN_Y,
- iWidth,
- iHeight,
- NULL,
- NULL,
- hInstance,
- NULL);
- if (hWnd == NULL) {
- MessageBoxEx(NULL, "CreateWindow() failed: Cannot create a window.", "Error", MB_OK, 0);
- return;
- }
- hDC = GetDC(hWnd);
- PIXELFORMATDESCRIPTOR pfd;
- memset(&pfd, 0, sizeof(pfd));
- pfd.nSize = sizeof(pfd);
- pfd.nVersion = 1;
- pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
- pfd.iPixelType = PFD_TYPE_RGBA;
- pfd.cColorBits = 32;
- pfd.cDepthBits = 32;
- pfd.iLayerType = PFD_MAIN_PLANE;
- const int pf = ChoosePixelFormat(hDC, &pfd);
- if (pf == 0) {
- MessageBoxEx(NULL, "ChoosePixelFormat() failed: Cannot find a suitable pixel format.", "Error", MB_OK, 0);
- return;
- }
- if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
- MessageBoxEx(NULL, "SetPixelFormat() failed: Cannot set format specified.", "Error", MB_OK, 0);
- return;
- }
- DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
- hRC = wglCreateContext(hDC);
- wglMakeCurrent(hDC, hRC);
- if (GH_START_FULLSCREEN) {
- ToggleFullscreen();
- }
- if (GH_HIDE_MOUSE) {
- ShowCursor(FALSE);
- }
- ShowWindow(hWnd, SW_SHOW);
- SetForegroundWindow(hWnd);
- SetFocus(hWnd);
- }
- void Engine::InitGLObjects() {
- //Initialize extensions
- glewInit();
- //Basic global variables
- glClearColor(0.6f, 0.9f, 1.0f, 1.0f);
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_LESS);
- glDepthMask(GL_TRUE);
- //Check GL functionality
- glGetQueryiv(GL_SAMPLES_PASSED_ARB, GL_QUERY_COUNTER_BITS_ARB, &occlusionCullingSupported);
- //Attempt to enalbe vsync (if failure then oh well)
- wglSwapIntervalEXT(1);
- }
- void Engine::DestroyGLObjects() {
- curScene->Unload();
- vObjects.clear();
- vPortals.clear();
- }
- void Engine::SetupInputs() {
- static const int HID_USAGE_PAGE_GENERIC = 0x01;
- static const int HID_USAGE_GENERIC_MOUSE = 0x02;
- static const int HID_USAGE_GENERIC_JOYSTICK = 0x04;
- static const int HID_USAGE_GENERIC_GAMEPAD = 0x05;
- RAWINPUTDEVICE Rid[3];
- //Mouse
- Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
- Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
- Rid[0].dwFlags = RIDEV_INPUTSINK;
- Rid[0].hwndTarget = hWnd;
- //Joystick
- Rid[1].usUsagePage = HID_USAGE_PAGE_GENERIC;
- Rid[1].usUsage = HID_USAGE_GENERIC_JOYSTICK;
- Rid[1].dwFlags = 0;
- Rid[1].hwndTarget = 0;
- //Gamepad
- Rid[2].usUsagePage = HID_USAGE_PAGE_GENERIC;
- Rid[2].usUsage = HID_USAGE_GENERIC_GAMEPAD;
- Rid[2].dwFlags = 0;
- Rid[2].hwndTarget = 0;
- RegisterRawInputDevices(Rid, 3, sizeof(Rid[0]));
- }
- void Engine::ConfineCursor() {
- if (GH_HIDE_MOUSE) {
- RECT rect;
- GetWindowRect(hWnd, &rect);
- SetCursorPos((rect.right + rect.left) / 2, (rect.top + rect.bottom) / 2);
- }
- }
- float Engine::NearestPortalDist() const {
- float dist = FLT_MAX;
- for (size_t i = 0; i < vPortals.size(); ++i) {
- dist = GH_MIN(dist, vPortals[i]->DistTo(player->pos));
- }
- return dist;
- }
- void Engine::ToggleFullscreen() {
- isFullscreen = !isFullscreen;
- if (isFullscreen) {
- iWidth = GetSystemMetrics(SM_CXSCREEN);
- iHeight = GetSystemMetrics(SM_CYSCREEN);
- SetWindowLong(hWnd, GWL_STYLE, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
- SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW);
- SetWindowPos(hWnd, HWND_TOPMOST, 0, 0,
- iWidth, iHeight, SWP_SHOWWINDOW);
- } else {
- iWidth = GH_SCREEN_WIDTH;
- iHeight = GH_SCREEN_HEIGHT;
- SetWindowLong(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
- SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);
- SetWindowPos(hWnd, HWND_TOP, GH_SCREEN_X, GH_SCREEN_Y,
- iWidth, iHeight, SWP_SHOWWINDOW);
- }
- }
- #pragma once
- #include "GameHeader.h"
- #include "Camera.h"
- #include "Input.h"
- #include "Object.h"
- #include "Portal.h"
- #include "Player.h"
- #include "Timer.h"
- #include "Scene.h"
- #include "Sky.h"
- #include <GL/glew.h>
- #include <windows.h>
- #include <memory>
- #include <vector>
- class Engine {
- public:
- Engine();
- ~Engine();
- int Run();
- void Update();
- void Render(const Camera& cam, GLuint curFBO, const Portal* skipPortal);
- void LoadScene(int ix);
- LRESULT WindowProc(HWND hCurWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- const Player& GetPlayer() const { return *player; }
- float NearestPortalDist() const;
- private:
- void CreateGLWindow();
- void InitGLObjects();
- void DestroyGLObjects();
- void SetupInputs();
- void ConfineCursor();
- void ToggleFullscreen();
- HDC hDC; // device context
- HGLRC hRC; // opengl context
- HWND hWnd; // window
- HINSTANCE hInstance; // process id
- LONG iWidth; // window width
- LONG iHeight; // window height
- bool isFullscreen; // fullscreen state
- Camera main_cam;
- Input input;
- Timer timer;
- std::vector<std::shared_ptr<Object>> vObjects;
- std::vector<std::shared_ptr<Portal>> vPortals;
- std::shared_ptr<Sky> sky;
- std::shared_ptr<Player> player;
- GLint occlusionCullingSupported;
- std::vector<std::shared_ptr<Scene>> vScenes;
- std::shared_ptr<Scene> curScene;
- };
- pragma once
- #include "Object.h"
- #include "Resources.h"
- #include "Portal.h"
- class Floorplan : public Object {
- public:
- Floorplan() {
- mesh = AquireMesh("floorplan.obj");
- shader = AquireShader("texture_array");
- texture = AquireTexture("floorplan_textures.bmp", 4, 4);
- scale = Vector3(0.1524f); //6-inches to meters
- }
- virtual ~Floorplan() {}
- void AddPortals(PPortalVec& pvec) const {
- std::shared_ptr<Portal> p1(new Portal);
- std::shared_ptr<Portal> p2(new Portal);
- std::shared_ptr<Portal> p3(new Portal);
- std::shared_ptr<Portal> p4(new Portal);
- std::shared_ptr<Portal> p5(new Portal);
- std::shared_ptr<Portal> p6(new Portal);
- p1->pos = Vector3(33, 10, 25.5f) * scale;
- p1->scale = Vector3(4, 10, 1) * scale;
- p2->pos = Vector3(74, 10, 25.5f) * scale;
- p2->scale = Vector3(4, 10, 1) * scale;
- p3->pos = Vector3(33, 10, 66.5f) * scale;
- p3->scale = Vector3(4, 10, 1) * scale;
- p4->pos = Vector3(63.5f, 10, 48) * scale;
- p4->scale = Vector3(4, 10, 1) * scale;
- p4->euler.y = GH_PI/2;
- p5->pos = Vector3(63.5f, 10, 7) * scale;
- p5->scale = Vector3(4, 10, 1) * scale;
- p5->euler.y = GH_PI / 2;
- p6->pos = Vector3(22.5f, 10, 48) * scale;
- p6->scale = Vector3(4, 10, 1) * scale;
- p6->euler.y = GH_PI / 2;
- Portal::Connect(p1->front, p3->back);
- Portal::Connect(p1->back, p2->front);
- Portal::Connect(p3->front, p2->back);
- Portal::Connect(p4->front, p6->back);
- Portal::Connect(p4->back, p5->front);
- Portal::Connect(p6->front, p5->back);
- pvec.push_back(p1);
- pvec.push_back(p2);
- pvec.push_back(p3);
- pvec.push_back(p4);
- pvec.push_back(p5);
- pvec.push_back(p6);
- }
- };
- #include "FrameBuffer.h"
- #include "GameHeader.h"
- #include "Engine.h"
- #include <iostream>
- FrameBuffer::FrameBuffer() {
- glGenTextures(1, &texId);
- glBindTexture(GL_TEXTURE_2D, texId);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GH_FBO_SIZE, GH_FBO_SIZE, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
- //-------------------------
- glGenFramebuffersEXT(1, &fbo);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texId, 0);
- //-------------------------
- glGenRenderbuffersEXT(1, &renderBuf);
- glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderBuf);
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, GH_FBO_SIZE, GH_FBO_SIZE);
- //-------------------------
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, renderBuf);
- //-------------------------
- //Does the GPU support current FBO configuration?
- GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
- if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- return;
- }
- //Unbind so future rendering can proceed normally
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- }
- void FrameBuffer::Use() {
- glBindTexture(GL_TEXTURE_2D, texId);
- }
- void FrameBuffer::Render(const Camera& cam, GLuint curFBO, const Portal* skipPortal) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
- glViewport(0, 0, GH_FBO_SIZE, GH_FBO_SIZE);
- GH_ENGINE->Render(cam, fbo, skipPortal);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, curFBO);
- }
- #pragma once
- #include "Camera.h"
- #include <GL/glew.h>
- //Forward declaration
- class Portal;
- class FrameBuffer {
- public:
- FrameBuffer();
- void Render(const Camera& cam, GLuint curFBO, const Portal* skipPortal);
- void Use();
- private:
- GLuint texId;
- GLuint fbo;
- GLuint renderBuf;
- };
- #pragma once
- #include <stdint.h>
- #pragma warning(disable : 4100) // Unreferenced formal parameter
- #pragma warning(disable : 4099) // Missing PDB file
- //Windows
- static const char GH_TITLE[] = "NonEuclideanDemo";
- static const char GH_CLASS[] = "NED";
- //General
- static const float GH_PI = 3.141592653589793f;
- static const int GH_MAX_PORTALS = 16;
- //Graphics
- static const bool GH_START_FULLSCREEN = false;
- static const bool GH_HIDE_MOUSE = true;
- static const bool GH_USE_SKY = true;
- static const int GH_SCREEN_WIDTH = 1280;
- static const int GH_SCREEN_HEIGHT = 720;
- static const int GH_SCREEN_X = 50;
- static const int GH_SCREEN_Y = 50;
- static const float GH_FOV = 60.0f;
- static const float GH_NEAR_MIN = 1e-3f;
- static const float GH_NEAR_MAX = 1e-1f;
- static const float GH_FAR = 100.0f;
- static const int GH_FBO_SIZE = 2048;
- static const int GH_MAX_RECURSION = 4;
- //Gameplay
- static const float GH_MOUSE_SENSITIVITY = 0.005f;
- static const float GH_MOUSE_SMOOTH = 0.5f;
- static const float GH_WALK_SPEED = 2.9f;
- static const float GH_WALK_ACCEL = 50.0f;
- static const float GH_BOB_FREQ = 8.0f;
- static const float GH_BOB_OFFS = 0.015f;
- static const float GH_BOB_DAMP = 0.04f;
- static const float GH_BOB_MIN = 0.1f;
- static const float GH_DT = 0.002f;
- static const int GH_MAX_STEPS = 30;
- static const float GH_PLAYER_HEIGHT = 1.5f;
- static const float GH_PLAYER_RADIUS = 0.2f;
- static const float GH_GRAVITY = -9.8f;
- //Global variables
- class Engine;
- class Input;
- class Player;
- extern Engine* GH_ENGINE;
- extern Player* GH_PLAYER;
- extern const Input* GH_INPUT;
- extern int GH_REC_LEVEL;
- extern int64_t GH_FRAME;
- //Functions
- template<class T>
- inline T GH_CLAMP(T a, T mn, T mx) {
- return a < mn ? mn : (a > mx ? mx : a);
- }
- template<class T>
- inline T GH_MIN(T a, T b) {
- return a < b ? a : b;
- }
- template<class T>
- inline T GH_MAX(T a, T b) {
- return a > b ? a : b;
- }
- #pragma once
- #include "Object.h"
- #include "Resources.h"
- class Ground : public Object {
- public:
- Ground(bool slope=false) {
- if (slope) {
- mesh = AquireMesh("ground_slope.obj");
- } else {
- mesh = AquireMesh("ground.obj");
- }
- shader = AquireShader("texture");
- texture = AquireTexture("checker_green.bmp");
- scale = Vector3(10, 1, 10);
- }
- virtual ~Ground() {}
- };
- #pragma once
- #include "Object.h"
- #include "Resources.h"
- class House : public Object {
- public:
- House(const char* tex) {
- mesh = AquireMesh("square_rooms.obj");
- shader = AquireShader("texture");
- texture = AquireTexture(tex);
- scale = Vector3(1.0f, 3.0f, 1.0f);
- }
- virtual ~House() {}
- void SetDoor1(Object& portal) const {
- portal.pos = LocalToWorld().MulPoint(Vector3(4.0f, 0.5f, 10.0f));
- portal.euler = euler;
- portal.scale = Vector3(2, 0.5f, 1) * scale;
- }
- void SetDoor2(Object& portal) const {
- portal.pos = LocalToWorld().MulPoint(Vector3(10.0f, 0.5f, 4.0f));
- portal.euler = euler;
- portal.euler.y -= GH_PI/2;
- portal.scale = Vector3(2, 0.5f, 1) * scale;
- }
- void SetDoor3(Object& portal) const {
- portal.pos = LocalToWorld().MulPoint(Vector3(16.0f, 0.5f, 10.0f));
- portal.euler = euler;
- portal.euler.y -= GH_PI;
- portal.scale = Vector3(2, 0.5f, 1) * scale;
- }
- void SetDoor4(Object& portal) const {
- portal.pos = LocalToWorld().MulPoint(Vector3(10.0f, 0.5f, 16.0f));
- portal.euler = euler;
- portal.euler.y -= GH_PI*3/2;
- portal.scale = Vector3(2, 0.5f, 1) * scale;
- }
- };
- #include "Input.h"
- #include "GameHeader.h"
- #include <Windows.h>
- #include <memory>
- Input::Input() {
- memset(this, 0, sizeof(Input));
- }
- void Input::EndFrame() {
- memset(key_press, 0, sizeof(key_press));
- memset(mouse_button_press, 0, sizeof(mouse_button_press));
- mouse_dx = mouse_dx * GH_MOUSE_SMOOTH + mouse_ddx * (1.0f - GH_MOUSE_SMOOTH);
- mouse_dy = mouse_dy * GH_MOUSE_SMOOTH + mouse_ddy * (1.0f - GH_MOUSE_SMOOTH);
- mouse_ddx = 0.0f;
- mouse_ddy = 0.0f;
- }
- void Input::UpdateRaw(const tagRAWINPUT* raw) {
- static BYTE buffer[2048];
- static UINT buffer_size = sizeof(buffer);
- if (raw->header.dwType == RIM_TYPEMOUSE) {
- if (raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE) {
- mouse_ddx += raw->data.mouse.lLastX;
- mouse_ddy += raw->data.mouse.lLastY;
- }
- if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) {
- mouse_button[0] = true;
- mouse_button_press[0] = true;
- }
- if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) {
- mouse_button[1] = true;
- mouse_button_press[1] = true;
- }
- if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) {
- mouse_button[2] = true;
- mouse_button_press[2] = true;
- }
- if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) mouse_button[0] = false;
- if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) mouse_button[1] = false;
- if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) mouse_button[2] = false;
- } else if (raw->header.dwType == RIM_TYPEHID) {
- //TODO:
- }
- }
- #pragma once
- struct tagRAWINPUT;
- class Input {
- public:
- Input();
- void EndFrame();
- void UpdateRaw(const tagRAWINPUT* raw);
- //Keyboard
- bool key[256];
- bool key_press[256];
- //Mouse
- bool mouse_button[3];
- bool mouse_button_press[3];
- float mouse_dx;
- float mouse_dy;
- float mouse_ddx;
- float mouse_ddy;
- //Joystick
- //TODO:
- //Bindings
- //TODO:
- //Calibration
- //TODO:
- };
- #include "Level1.h"
- #include "Tunnel.h"
- #include "Ground.h"
- void Level1::Load(PObjectVec& objs, PPortalVec& portals, Player& player) {
- std::shared_ptr<Tunnel> tunnel1(new Tunnel(Tunnel::NORMAL));
- tunnel1->pos = Vector3(-2.4f, 0, -1.8f);
- tunnel1->scale = Vector3(1, 1, 4.8f);
- objs.push_back(tunnel1);
- std::shared_ptr<Tunnel> tunnel2(new Tunnel(Tunnel::NORMAL));
- tunnel2->pos = Vector3(2.4f, 0, 0);
- tunnel2->scale = Vector3(1, 1, 0.6f);
- objs.push_back(tunnel2);
- std::shared_ptr<Ground> ground(new Ground());
- ground->scale *= 1.2f;
- objs.push_back(ground);
- std::shared_ptr<Portal> portal1(new Portal());
- tunnel1->SetDoor1(*portal1);
- portals.push_back(portal1);
- std::shared_ptr<Portal> portal2(new Portal());
- tunnel2->SetDoor1(*portal2);
- portals.push_back(portal2);
- std::shared_ptr<Portal> portal3(new Portal());
- tunnel1->SetDoor2(*portal3);
- portals.push_back(portal3);
- std::shared_ptr<Portal> portal4(new Portal());
- tunnel2->SetDoor2(*portal4);
- portals.push_back(portal4);
- Portal::Connect(portal1, portal2);
- Portal::Connect(portal3, portal4);
- player.SetPosition(Vector3(0, GH_PLAYER_HEIGHT, 5));
- }
- #pragma once
- #include "Scene.h"
- class Level1 : public Scene {
- public:
- virtual void Load(PObjectVec& objs, PPortalVec& portals, Player& player) override;
- };
- #include "Level2.h"
- #include "House.h"
- void Level2::Load(PObjectVec& objs, PPortalVec& portals, Player& player) {
- std::shared_ptr<House> house1(new House("three_room.bmp"));
- house1->pos = Vector3(0, 0, -20);
- objs.push_back(house1);
- std::shared_ptr<House> house2;
- if (num_rooms > 4) {
- house2.reset(new House("three_room2.bmp"));
- house2->pos = Vector3(200, 0, -20);
- objs.push_back(house2);
- }
- if (num_rooms == 1) {
- std::shared_ptr<Portal> portal1(new Portal());
- house1->SetDoor1(*portal1);
- portals.push_back(portal1);
- std::shared_ptr<Portal> portal2(new Portal());
- house1->SetDoor4(*portal2);
- portals.push_back(portal2);
- Portal::Connect(portal1, portal2);
- } else if (num_rooms == 2) {
- std::shared_ptr<Portal> portal1(new Portal());
- house1->SetDoor2(*portal1);
- portals.push_back(portal1);
- std::shared_ptr<Portal> portal2(new Portal());
- house1->SetDoor4(*portal2);
- portals.push_back(portal2);
- Portal::Connect(portal1, portal2);
- } else if (num_rooms == 3) {
- std::shared_ptr<Portal> portal1(new Portal());
- house1->SetDoor3(*portal1);
- portals.push_back(portal1);
- std::shared_ptr<Portal> portal2(new Portal());
- house1->SetDoor4(*portal2);
- portals.push_back(portal2);
- Portal::Connect(portal1, portal2);
- } else if (num_rooms == 4) {
- } else if (num_rooms == 5) {
- std::shared_ptr<Portal> portal1(new Portal());
- house1->SetDoor4(*portal1);
- portals.push_back(portal1);
- std::shared_ptr<Portal> portal2(new Portal());
- house2->SetDoor2(*portal2);
- portals.push_back(portal2);
- std::shared_ptr<Portal> portal3(new Portal());
- house2->SetDoor1(*portal3);
- portals.push_back(portal3);
- Portal::Connect(portal1->front, portal2->back);
- Portal::Connect(portal2->front, portal3->back);
- Portal::Connect(portal3->front, portal1->back);
- } else if (num_rooms == 6) {
- std::shared_ptr<Portal> portal1(new Portal());
- house1->SetDoor4(*portal1);
- portals.push_back(portal1);
- std::shared_ptr<Portal> portal2(new Portal());
- house2->SetDoor3(*portal2);
- portals.push_back(portal2);
- std::shared_ptr<Portal> portal3(new Portal());
- house2->SetDoor1(*portal3);
- portals.push_back(portal3);
- Portal::Connect(portal1->front, portal2->back);
- Portal::Connect(portal2->front, portal3->back);
- Portal::Connect(portal3->front, portal1->back);
- }
- player.SetPosition(Vector3(3, GH_PLAYER_HEIGHT, 3));
- }
- #pragma once
- #include "Scene.h"
- class Level2 : public Scene {
- public:
- Level2(int rooms) : num_rooms(rooms) {}
- virtual void Load(PObjectVec& objs, PPortalVec& portals, Player& player) override;
- private:
- int num_rooms;
- };
- #include "Level3.h"
- #include "Pillar.h"
- #include "Ground.h"
- #include "Statue.h"
- #include "PillarRoom.h"
- void Level3::Load(PObjectVec& objs, PPortalVec& portals, Player& player) {
- //Room 1
- std::shared_ptr<Pillar> pillar1(new Pillar);
- objs.push_back(pillar1);
- std::shared_ptr<PillarRoom> pillarRoom1(new PillarRoom);
- objs.push_back(pillarRoom1);
- std::shared_ptr<Ground> ground1(new Ground);
- ground1->scale *= 2.0f;
- objs.push_back(ground1);
- std::shared_ptr<Statue> statue1(new Statue("teapot.obj"));
- statue1->pos = Vector3(0, 0.5f, 9);
- statue1->scale = Vector3(0.5f);
- statue1->euler.y = GH_PI / 2;
- objs.push_back(statue1);
- //Room 2
- std::shared_ptr<Pillar> pillar2(new Pillar);
- pillar2->pos = Vector3(200, 0, 0);
- objs.push_back(pillar2);
- std::shared_ptr<PillarRoom> pillarRoom2(new PillarRoom);
- pillarRoom2->pos = Vector3(200, 0, 0);
- objs.push_back(pillarRoom2);
- std::shared_ptr<Ground> ground2(new Ground);
- ground2->pos = Vector3(200, 0, 0);
- ground2->scale *= 2.0f;
- objs.push_back(ground2);
- std::shared_ptr<Statue> statue2(new Statue("bunny.obj"));
- statue2->pos = Vector3(200, -0.4f, 9);
- statue2->scale = Vector3(14.0f);
- statue2->euler.y = GH_PI;
- objs.push_back(statue2);
- //Room 3
- std::shared_ptr<Pillar> pillar3(new Pillar);
- pillar3->pos = Vector3(400, 0, 0);
- objs.push_back(pillar3);
- std::shared_ptr<PillarRoom> pillarRoom3(new PillarRoom);
- pillarRoom3->pos = Vector3(400, 0, 0);
- objs.push_back(pillarRoom3);
- std::shared_ptr<Ground> ground3(new Ground);
- ground3->pos = Vector3(400, 0, 0);
- ground3->scale *= 2.0f;
- objs.push_back(ground3);
- std::shared_ptr<Statue> statue3(new Statue("suzanne.obj"));
- statue3->pos = Vector3(400, 0.9f, 9);
- statue3->scale = Vector3(1.2f);
- statue3->euler.y = GH_PI;
- objs.push_back(statue3);
- //Portals
- std::shared_ptr<Portal> portal1(new Portal);
- pillarRoom1->SetPortal(*portal1);
- portals.push_back(portal1);
- std::shared_ptr<Portal> portal2(new Portal);
- pillarRoom2->SetPortal(*portal2);
- portals.push_back(portal2);
- std::shared_ptr<Portal> portal3(new Portal);
- pillarRoom3->SetPortal(*portal3);
- portals.push_back(portal3);
- Portal::Connect(portal1->front, portal2->back);
- Portal::Connect(portal2->front, portal3->back);
- Portal::Connect(portal3->front, portal1->back);
- player.SetPosition(Vector3(0, GH_PLAYER_HEIGHT, 3));
- }
- #pragma once
- #include "Scene.h"
- class Level3 : public Scene {
- public:
- virtual void Load(PObjectVec& objs, PPortalVec& portals, Player& player) override;
- };
- #include "Level4.h"
- #include "Tunnel.h"
- #include "Ground.h"
- void Level4::Load(PObjectVec& objs, PPortalVec& portals, Player& player) {
- std::shared_ptr<Tunnel> tunnel1(new Tunnel(Tunnel::SLOPE));
- tunnel1->pos = Vector3(0, 0, 0);
- tunnel1->scale = Vector3(1, 1, 5);
- tunnel1->euler.y = GH_PI;
- objs.push_back(tunnel1);
- std::shared_ptr<Ground> ground1(new Ground(true));
- ground1->scale *= Vector3(1, 2, 1);
- objs.push_back(ground1);
- std::shared_ptr<Tunnel> tunnel2(new Tunnel(Tunnel::SLOPE));
- tunnel2->pos = Vector3(200, 0, 0);
- tunnel2->scale = Vector3(1, 1, 5);
- objs.push_back(tunnel2);
- std::shared_ptr<Ground> ground2(new Ground(true));
- ground2->pos = Vector3(200, 0, 0);
- ground2->scale *= Vector3(1, 2, 1);
- ground2->euler.y = GH_PI;
- objs.push_back(ground2);
- std::shared_ptr<Portal> portal1(new Portal());
- tunnel1->SetDoor1(*portal1);
- portals.push_back(portal1);
- std::shared_ptr<Portal> portal2(new Portal());
- tunnel1->SetDoor2(*portal2);
- portals.push_back(portal2);
- std::shared_ptr<Portal> portal3(new Portal());
- tunnel2->SetDoor1(*portal3);
- portal3->euler.y -= GH_PI;
- portals.push_back(portal3);
- std::shared_ptr<Portal> portal4(new Portal());
- tunnel2->SetDoor2(*portal4);
- portal4->euler.y -= GH_PI;
- portals.push_back(portal4);
- Portal::Connect(portal1, portal4);
- Portal::Connect(portal2, portal3);
- player.SetPosition(Vector3(0, GH_PLAYER_HEIGHT - 2, 8));
- }
- #include "Level4.h"
- #include "Tunnel.h"
- #include "Ground.h"
- void Level4::Load(PObjectVec& objs, PPortalVec& portals, Player& player) {
- std::shared_ptr<Tunnel> tunnel1(new Tunnel(Tunnel::SLOPE));
- tunnel1->pos = Vector3(0, 0, 0);
- tunnel1->scale = Vector3(1, 1, 5);
- tunnel1->euler.y = GH_PI;
- objs.push_back(tunnel1);
- std::shared_ptr<Ground> ground1(new Ground(true));
- ground1->scale *= Vector3(1, 2, 1);
- objs.push_back(ground1);
- std::shared_ptr<Tunnel> tunnel2(new Tunnel(Tunnel::SLOPE));
- tunnel2->pos = Vector3(200, 0, 0);
- tunnel2->scale = Vector3(1, 1, 5);
- objs.push_back(tunnel2);
- std::shared_ptr<Ground> ground2(new Ground(true));
- ground2->pos = Vector3(200, 0, 0);
- ground2->scale *= Vector3(1, 2, 1);
- ground2->euler.y = GH_PI;
- objs.push_back(ground2);
- std::shared_ptr<Portal> portal1(new Portal());
- tunnel1->SetDoor1(*portal1);
- portals.push_back(portal1);
- std::shared_ptr<Portal> portal2(new Portal());
- tunnel1->SetDoor2(*portal2);
- portals.push_back(portal2);
- std::shared_ptr<Portal> portal3(new Portal());
- tunnel2->SetDoor1(*portal3);
- portal3->euler.y -= GH_PI;
- portals.push_back(portal3);
- std::shared_ptr<Portal> portal4(new Portal());
- tunnel2->SetDoor2(*portal4);
- portal4->euler.y -= GH_PI;
- portals.push_back(portal4);
- Portal::Connect(portal1, portal4);
- Portal::Connect(portal2, portal3);
- player.SetPosition(Vector3(0, GH_PLAYER_HEIGHT - 2, 8));
- }
- #include "Level5.h"
- #include "Tunnel.h"
- #include "Ground.h"
- void Level5::Load(PObjectVec& objs, PPortalVec& portals, Player& player) {
- std::shared_ptr<Tunnel> tunnel1(new Tunnel(Tunnel::SCALE));
- tunnel1->pos = Vector3(-1.2f, 0, 0);
- tunnel1->scale = Vector3(1, 1, 2.4f);
- objs.push_back(tunnel1);
- std::shared_ptr<Ground> ground1(new Ground());
- ground1->scale *= 1.2f;
- objs.push_back(ground1);
- std::shared_ptr<Tunnel> tunnel2(new Tunnel(Tunnel::NORMAL));
- tunnel2->pos = Vector3(201.2f, 0, 0);
- tunnel2->scale = Vector3(1, 1, 2.4f);
- objs.push_back(tunnel2);
- std::shared_ptr<Ground> ground2(new Ground());
- ground2->pos = Vector3(200, 0, 0);
- ground2->scale *= 1.2f;
- objs.push_back(ground2);
- std::shared_ptr<Portal> portal1(new Portal());
- tunnel1->SetDoor1(*portal1);
- portals.push_back(portal1);
- std::shared_ptr<Portal> portal2(new Portal());
- tunnel2->SetDoor1(*portal2);
- portals.push_back(portal2);
- std::shared_ptr<Portal> portal3(new Portal());
- tunnel1->SetDoor2(*portal3);
- portals.push_back(portal3);
- std::shared_ptr<Portal> portal4(new Portal());
- tunnel2->SetDoor2(*portal4);
- portals.push_back(portal4);
- Portal::Connect(portal1, portal2);
- Portal::Connect(portal3, portal4);
- std::shared_ptr<Tunnel> tunnel3(new Tunnel(Tunnel::NORMAL));
- tunnel3->pos = Vector3(-1, 0, -4.2f);
- tunnel3->scale = Vector3(0.25f, 0.25f, 0.6f);
- tunnel3->euler.y = GH_PI/2;
- objs.push_back(tunnel3);
- player.SetPosition(Vector3(0, GH_PLAYER_HEIGHT, 5));
- }
- #pragma once
- #include "Scene.h"
- class Level5 : public Scene {
- public:
- virtual void Load(PObjectVec& objs, PPortalVec& portals, Player& player) override;
- };
- #include "Level6.h"
- #include "Floorplan.h"
- void Level6::Load(PObjectVec& objs, PPortalVec& portals, Player& player) {
- std::shared_ptr<Floorplan> floorplan(new Floorplan);
- objs.push_back(floorplan);
- floorplan->AddPortals(portals);
- player.SetPosition(Vector3(2, GH_PLAYER_HEIGHT, 2));
- }
- #pragma once
- #include "Scene.h"
- class Level6 : public Scene {
- public:
- virtual void Load(PObjectVec& objs, PPortalVec& portals, Player& player) override;
- };
- #define _CRT_SECURE_NO_WARNINGS
- #include "Engine.h"
- int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst, LPSTR lpszCmdLine, int nCmdShow) {
- //Open console in debug mode
- #ifdef _DEBUG
- AllocConsole();
- //SetWindowPos(GetConsoleWindow(), 0, 1920, 200, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
- AttachConsole(GetCurrentProcessId());
- freopen("CON", "w", stdout);
- #endif
- //Run the main engine
- Engine engine;
- return engine.Run();
- }
- #include "Mesh.h"
- #include "Vector.h"
- #include <fstream>
- #include <sstream>
- #include <string>
- #include <cassert>
- Mesh::Mesh(const char* fname) {
- //Open the file for reading
- std::ifstream fin(std::string("Meshes/") + fname);
- if (!fin) {
- return;
- }
- //Temporaries
- std::vector<float> vert_palette;
- std::vector<float> uv_palette;
- bool is3DTex = false;
- //Read the file
- std::string line;
- while (!fin.eof()) {
- std::getline(fin, line);
- if (line.find("v ") == 0) {
- std::stringstream ss(line.c_str() + 2);
- float x, y, z;
- ss >> x >> y >> z;
- vert_palette.push_back(x);
- vert_palette.push_back(y);
- vert_palette.push_back(z);
- } else if (line.find("vt ") == 0) {
- std::stringstream ss(line.c_str() + 3);
- float u, v, w;
- ss >> u >> v >> w;
- uv_palette.push_back(u);
- uv_palette.push_back(v);
- if (!ss.fail()) {
- uv_palette.push_back(w);
- is3DTex = true;
- }
- } else if (line.find("c ") == 0) {
- uint32_t a = 0, b = 0, c = 0;
- if (line[2] == '*') {
- const uint32_t v_ix = (uint32_t)vert_palette.size() / 3;
- a = v_ix - 2; b = v_ix - 1; c = v_ix;
- } else {
- std::stringstream ss(line.c_str() + 2);
- ss >> a >> b >> c;
- }
- const Vector3 v1(&vert_palette[(a - 1) * 3]);
- const Vector3 v2(&vert_palette[(b - 1) * 3]);
- const Vector3 v3(&vert_palette[(c - 1) * 3]);
- colliders.push_back(Collider(v1, v2, v3));
- } else if (line.find("f ") == 0) {
- //Count the slashes
- int num_slashes = 0;
- size_t last_slash_ix = 0;
- bool doubleslash = false;
- for (size_t i = 0; i < line.size(); ++i) {
- if (line[i] == '/') {
- line[i] = ' ';
- if (last_slash_ix == i - 1) {
- assert(vert_palette.size() == uv_palette.size() || uv_palette.empty());
- doubleslash = true;
- }
- last_slash_ix = i;
- num_slashes++;
- }
- }
- uint32_t a=0, b=0, c=0, d=0;
- uint32_t at=0, bt=0, ct=0, dt=0;
- uint32_t _tmp;
- std::stringstream ss(line.c_str() + 2);
- const bool wild = (line[2] == '*');
- const bool wild2 = (line[3] == '*');
- bool isQuad = false;
- //Interpret face based on slash
- if (wild) {
- assert(num_slashes == 0);
- const uint32_t v_ix = (uint32_t)vert_palette.size() / 3;
- const uint32_t t_ix = (uint32_t)uv_palette.size() / (is3DTex ? 3 : 2);
- if (wild2) {
- a = v_ix - 3; b = v_ix - 2; c = v_ix - 1; d = v_ix - 0;
- at = t_ix - 3; bt = t_ix - 2; ct = t_ix - 1; dt = t_ix - 0;
- isQuad = true;
- } else {
- a = v_ix - 2; b = v_ix - 1; c = v_ix;
- at = t_ix - 2; bt = t_ix - 1; ct = t_ix;
- }
- } else if (num_slashes == 0) {
- ss >> a >> b >> c >> d;
- at = a; bt = b; ct = c; dt = d;
- if (!ss.fail()) {
- isQuad = true;
- }
- } else if (num_slashes == 3) {
- ss >> a >> at >> b >> bt >> c >> ct;
- } else if (num_slashes == 4) {
- isQuad = true;
- ss >> a >> at >> b >> bt >> c >> ct >> d >> dt;
- } else if (num_slashes == 6) {
- if (doubleslash) {
- ss >> a >> _tmp >> b >> _tmp >> c >> _tmp;
- at = a; bt = b; ct = c;
- } else {
- ss >> a >> at >> _tmp >> b >> bt >> _tmp >> c >> ct >> _tmp;
- }
- } else if (num_slashes == 8) {
- isQuad = true;
- if (doubleslash) {
- ss >> a >> _tmp >> b >> _tmp >> c >> _tmp >> d >> _tmp;
- at = a; bt = b; ct = c; dt = d;
- } else {
- ss >> a >> at >> _tmp >> b >> bt >> _tmp >> c >> ct >> _tmp >> d >> dt >> _tmp;
- }
- } else {
- assert(false);
- continue;
- }
- //Add face to list
- AddFace(vert_palette, uv_palette, a, at, b, bt, c, ct, is3DTex);
- if (isQuad) {
- AddFace(vert_palette, uv_palette, c, ct, d, dt, a, at, is3DTex);
- }
- }
- }
- //Setup GL
- glGenVertexArrays(1, &vao);
- glBindVertexArray(vao);
- glGenBuffers(NUM_VBOS, vbo);
- {
- glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
- glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(verts[0]), verts.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
- }
- {
- glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
- glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(uvs[0]), uvs.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, (is3DTex ? 3 : 2), GL_FLOAT, GL_FALSE, 0, 0);
- }
- {
- glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
- glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(normals[0]), normals.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(2);
- glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
- }
- }
- Mesh::~Mesh() {
- glDeleteBuffers(NUM_VBOS, vbo);
- glDeleteVertexArrays(1, &vao);
- }
- void Mesh::Draw() {
- glBindVertexArray(vao);
- glDrawArrays(GL_TRIANGLES, 0, (GLsizei)verts.size());
- }
- void Mesh::DebugDraw(const Camera& cam, const Matrix4& objMat) {
- for (size_t i = 0; i < colliders.size(); ++i) {
- colliders[i].DebugDraw(cam, objMat);
- }
- }
- void Mesh::AddFace(
- const std::vector<float>& vert_palette, const std::vector<float>& uv_palette,
- uint32_t a, uint32_t at, uint32_t b, uint32_t bt, uint32_t c, uint32_t ct, bool is3DTex)
- {
- //Merge texture and vertex indicies
- assert(a > 0 && b > 0 && c > 0);
- assert(at > 0 && bt > 0 && ct > 0);
- a -= 1; b -= 1; c -= 1;
- at -= 1; bt -= 1; ct -= 1;
- const uint32_t v_ix[3] = { a, b, c };
- const uint32_t uv_ix[3] = { at, bt, ct };
- //Calcuate the normal for this face
- const Vector3 v1(&vert_palette[a * 3]);
- const Vector3 v2(&vert_palette[b * 3]);
- const Vector3 v3(&vert_palette[c * 3]);
- const Vector3 normal = (v2 - v1).Cross(v3 - v1).Normalized();
- for (int i = 0; i < 3; ++i) {
- const uint32_t v = v_ix[i];
- const uint32_t vt = uv_ix[i];
- assert(v < vert_palette.size() / 3);
- verts.push_back(vert_palette[v * 3]);
- verts.push_back(vert_palette[v * 3 + 1]);
- verts.push_back(vert_palette[v * 3 + 2]);
- if (!uv_palette.empty()) {
- if (is3DTex) {
- assert(vt < uv_palette.size() / 3);
- uvs.push_back(uv_palette[vt * 3]);
- uvs.push_back(uv_palette[vt * 3 + 1]);
- uvs.push_back(uv_palette[vt * 3 + 2]);
- } else {
- assert(vt < uv_palette.size() / 2);
- uvs.push_back(uv_palette[vt * 2]);
- uvs.push_back(uv_palette[vt * 2 + 1]);
- }
- } else {
- uvs.push_back(0.0f);
- uvs.push_back(0.0f);
- }
- normals.push_back(normal.x);
- normals.push_back(normal.y);
- normals.push_back(normal.z);
- }
- }
- #pragma once
- #include "Collider.h"
- #include "Camera.h"
- #include <GL/glew.h>
- #include <vector>
- #include <map>
- class Mesh {
- public:
- static const int NUM_VBOS = 3;
- Mesh(const char* fname);
- ~Mesh();
- void Draw();
- void DebugDraw(const Camera& cam, const Matrix4& objMat);
- std::vector<Collider> colliders;
- private:
- void AddFace(
- const std::vector<float>& vert_palette, const std::vector<float>& uv_palette,
- uint32_t a, uint32_t at, uint32_t b, uint32_t bt, uint32_t c, uint32_t ct, bool is3DTex);
- GLuint vao;
- GLuint vbo[NUM_VBOS];
- std::vector<float> verts;
- std::vector<float> uvs;
- std::vector<float> normals;
- };
- #include "Object.h"
- #include "Mesh.h"
- #include "Shader.h"
- #include "Texture.h"
- Object::Object() :
- pos(0.0f),
- euler(0.0f),
- scale(1.0f),
- p_scale(1.0f) {
- }
- void Object::Reset() {
- pos.SetZero();
- euler.SetZero();
- scale.SetOnes();
- p_scale = 1.0f;
- }
- void Object::Draw(const Camera& cam, uint32_t curFBO) {
- if (shader && mesh) {
- const Matrix4 mv = WorldToLocal().Transposed();
- const Matrix4 mvp = cam.Matrix() * LocalToWorld();
- shader->Use();
- if (texture) {
- texture->Use();
- }
- shader->SetMVP(mvp.m, mv.m);
- mesh->Draw();
- }
- }
- Vector3 Object::Forward() const {
- return -(Matrix4::RotZ(euler.z) * Matrix4::RotX(euler.x) * Matrix4::RotY(euler.y)).ZAxis();
- }
- Matrix4 Object::LocalToWorld() const {
- return Matrix4::Trans(pos) * Matrix4::RotY(euler.y) * Matrix4::RotX(euler.x) * Matrix4::RotZ(euler.z) * Matrix4::Scale(scale * p_scale);
- }
- Matrix4 Object::WorldToLocal() const {
- return Matrix4::Scale(1.0f / (scale * p_scale)) * Matrix4::RotZ(-euler.z) * Matrix4::RotX(-euler.x) * Matrix4::RotY(-euler.y) * Matrix4::Trans(-pos);
- }
- void Object::DebugDraw(const Camera& cam) {
- if (mesh) {
- mesh->DebugDraw(cam, LocalToWorld());
- }
- }
- #pragma once
- #include "GameHeader.h"
- #include "Vector.h"
- #include "Camera.h"
- #include "Sphere.h"
- #include <vector>
- #include <memory>
- //Forward declarations
- class Physical;
- class Mesh;
- class Texture;
- class Shader;
- class Object {
- public:
- Object();
- virtual ~Object() {}
- virtual void Reset();
- virtual void Draw(const Camera& cam, uint32_t curFBO);
- virtual void Update() {};
- virtual void OnHit(Object& other, Vector3& push) {};
- //Casts
- virtual Physical* AsPhysical() { return nullptr; }
- const Physical* AsPhysical() const { return const_cast<Object*>(this)->AsPhysical(); }
- void DebugDraw(const Camera& cam);
- Matrix4 LocalToWorld() const;
- Matrix4 WorldToLocal() const;
- Vector3 Forward() const;
- Vector3 pos;
- Vector3 euler;
- Vector3 scale;
- // Physical scale, only updated by portal scale changes
- float p_scale;
- std::shared_ptr<Mesh> mesh;
- std::shared_ptr<Texture> texture;
- std::shared_ptr<Shader> shader;
- };
- typedef std::vector<std::shared_ptr<Object>> PObjectVec;
- #include "Physical.h"
- #include "GameHeader.h"
- Physical::Physical() {
- Reset();
- }
- void Physical::Reset() {
- Object::Reset();
- velocity.SetZero();
- gravity.Set(0.0f, GH_GRAVITY, 0.0f);
- bounce = 0.0f;
- friction = 0.0f;
- high_friction = 0.0f;
- drag = 0.0f;
- prev_pos.SetZero();
- }
- void Physical::Update() {
- prev_pos = pos;
- velocity += gravity * p_scale * GH_DT;
- velocity *= (1.0f - drag);
- pos += velocity * GH_DT;
- }
- void Physical::OnCollide(Object& other, const Vector3& push) {
- //Update position to avoid collision
- pos += push;
- //Ignore push if delta is too small
- if (push.MagSq() < 1e-8f * p_scale) {
- return;
- }
- //Calculate kinetic friction
- float kinetic_friction = friction;
- if (high_friction > 0.0f) {
- const float vel_ratio = velocity.Mag() / (high_friction * p_scale);
- kinetic_friction = GH_MIN(friction * (vel_ratio + 5.0f) / (vel_ratio + 1.0f), 1.0f);
- }
- //Update velocity to react to collision
- const Vector3 push_proj = push * (velocity.Dot(push) / push.Dot(push));
- velocity = (velocity - push_proj) * (1.0f - kinetic_friction) - push_proj * bounce;
- }
- bool Physical::TryPortal(const Portal& portal) {
- const Vector3 bump = portal.GetBump(prev_pos) * (2 * GH_NEAR_MIN * p_scale);
- const Portal::Warp* warp = portal.Intersects(prev_pos, pos, bump);
- if (warp) {
- //Teleport object
- pos = warp->deltaInv.MulPoint(pos - bump * 2);
- velocity = warp->deltaInv.MulDirection(velocity);
- prev_pos = pos;
- //Update camera direction
- const Vector3 forward(-std::sin(euler.y), 0, -std::cos(euler.y));
- const Vector3 newDir = warp->deltaInv.MulDirection(forward);
- euler.y = -std::atan2(newDir.x, -newDir.z);
- //Update object scale
- p_scale *= warp->deltaInv.XAxis().Mag();
- return true;
- }
- return false;
- }
- #pragma once
- #include "Object.h"
- #include "Portal.h"
- #include "Sphere.h"
- class Physical : public Object {
- public:
- Physical();
- virtual ~Physical() override {}
- virtual void Reset() override;
- virtual void Update() override;
- virtual void OnCollide(Object& other, const Vector3& push);
- void SetPosition(const Vector3& _pos) {
- pos = _pos;
- prev_pos = _pos;
- }
- bool TryPortal(const Portal& portal);
- virtual Physical* AsPhysical() override { return this; }
- Vector3 gravity;
- Vector3 velocity;
- float bounce;
- float friction;
- float high_friction;
- float drag;
- Vector3 prev_pos;
- std::vector<Sphere> hitSpheres;
- };
- #pragma once
- #include "Object.h"
- #include "Resources.h"
- class Pillar : public Object {
- public:
- Pillar() {
- mesh = AquireMesh("pillar.obj");
- shader = AquireShader("texture");
- texture = AquireTexture("white.bmp");
- scale = Vector3(0.1f);
- }
- virtual ~Pillar() {}
- };
- #pragma once
- #include "Object.h"
- #include "Resources.h"
- class PillarRoom : public Object {
- public:
- PillarRoom() {
- mesh = AquireMesh("pillar_room.obj");
- shader = AquireShader("texture");
- texture = AquireTexture("three_room.bmp");
- scale = Vector3(1.1f);
- }
- void SetPortal(Object& portal) const {
- portal.pos = LocalToWorld().MulPoint(Vector3(0, 1.5f, -1));
- portal.euler = euler;
- portal.euler.y -= GH_PI / 2;
- portal.scale = Vector3(1, 1.5f, 1) * scale;
- }
- virtual ~PillarRoom() {}
- };
- #include "Player.h"
- #include "Input.h"
- #include "GameHeader.h"
- #include <Windows.h>
- #include <iostream>
- Player::Player() {
- Reset();
- hitSpheres.push_back(Sphere(Vector3(0, 0, 0), GH_PLAYER_RADIUS));
- hitSpheres.push_back(Sphere(Vector3(0, GH_PLAYER_RADIUS - GH_PLAYER_HEIGHT, 0), GH_PLAYER_RADIUS));
- }
- void Player::Reset() {
- Physical::Reset();
- cam_rx = 0.0f;
- cam_ry = 0.0f;
- bob_mag = 0.0f;
- bob_phi = 0.0f;
- friction = 0.04f;
- drag = 0.002f;
- onGround = true;
- }
- void Player::Update() {
- //Update bobbing motion
- float magT = (prev_pos - pos).Mag() / (GH_DT * p_scale);
- if (!onGround) { magT = 0.0f; }
- bob_mag = bob_mag*(1.0f - GH_BOB_DAMP) + magT*GH_BOB_DAMP;
- if (bob_mag < GH_BOB_MIN) {
- bob_phi = 0.0f;
- } else {
- bob_phi += GH_BOB_FREQ * GH_DT;
- if (bob_phi > 2 * GH_PI) {
- bob_phi -= 2 * GH_PI;
- }
- }
- //Physics
- Physical::Update();
- //Looking
- Look(GH_INPUT->mouse_dx, GH_INPUT->mouse_dy);
- //Movement
- float moveF = 0.0f;
- float moveL = 0.0f;
- if (GH_INPUT->key['W']) {
- moveF += 1.0f;
- }
- if (GH_INPUT->key['S']) {
- moveF -= 1.0f;
- }
- if (GH_INPUT->key['A']) {
- moveL += 1.0f;
- }
- if (GH_INPUT->key['D']) {
- moveL -= 1.0f;
- }
- Move(moveF, moveL);
- #if 0
- //Jumping
- if (onGround && GH_INPUT->key[VK_SPACE]) {
- velocity.y += 2.0f * p_scale;
- }
- #endif
- //Reset ground state after update finishes
- onGround = false;
- }
- void Player::Look(float mouseDx, float mouseDy) {
- //Adjust x-axis rotation
- cam_rx -= mouseDy * GH_MOUSE_SENSITIVITY;
- if (cam_rx > GH_PI / 2) {
- cam_rx = GH_PI / 2;
- } else if (cam_rx < -GH_PI / 2) {
- cam_rx = -GH_PI / 2;
- }
- //Adjust y-axis rotation
- cam_ry -= mouseDx * GH_MOUSE_SENSITIVITY;
- if (cam_ry > GH_PI) {
- cam_ry -= GH_PI * 2;
- } else if (cam_ry < -GH_PI) {
- cam_ry += GH_PI * 2;
- }
- }
- void Player::Move(float moveF, float moveL) {
- //Make sure movement is not too fast
- const float mag = std::sqrt(moveF*moveF + moveL*moveL);
- if (mag > 1.0f) {
- moveF /= mag;
- moveL /= mag;
- }
- //Movement
- const Matrix4 camToWorld = LocalToWorld() * Matrix4::RotY(cam_ry);
- velocity += camToWorld.MulDirection(Vector3(-moveL, 0, -moveF)) * (GH_WALK_ACCEL * GH_DT);
- //Don't allow non-falling speeds above the player's max speed
- const float tempY = velocity.y;
- velocity.y = 0.0f;
- velocity.ClipMag(p_scale * GH_WALK_SPEED);
- velocity.y = tempY;
- }
- void Player::OnCollide(Object& other, const Vector3& push) {
- //Prevent player from rolling down hills if they're not too steep
- Vector3 newPush = push;
- if (push.Normalized().y > 0.7f) {
- newPush.x = 0.0f;
- newPush.z = 0.0f;
- onGround = true;
- }
- //Friction should only apply when player is on ground
- const float cur_friction = friction;
- if (!onGround) {
- friction = 0.0f;
- }
- //Base call
- Physical::OnCollide(other, newPush);
- friction = cur_friction;
- }
- Matrix4 Player::WorldToCam() const {
- return Matrix4::RotX(-cam_rx) * Matrix4::RotY(-cam_ry) * Matrix4::Trans(-CamOffset()) * WorldToLocal();
- }
- Matrix4 Player::CamToWorld() const {
- return LocalToWorld() * Matrix4::Trans(CamOffset()) * Matrix4::RotY(cam_ry) * Matrix4::RotX(cam_rx);
- }
- Vector3 Player::CamOffset() const {
- //If bob is too small, don't even bother
- if (bob_mag < GH_BOB_MIN) {
- return Vector3::Zero();
- }
- //Convert bob to translation
- const float theta = (GH_PI/2) * std::sin(bob_phi);
- const float y = bob_mag * GH_BOB_OFFS * (1.0f - std::cos(theta));
- return Vector3(0, y, 0);
- }
- #pragma once
- #include "Vector.h"
- #include "Physical.h"
- class Player : public Physical {
- public:
- Player();
- virtual ~Player() override {}
- virtual void Reset() override;
- virtual void Update() override;
- virtual void OnCollide(Object& other, const Vector3& push) override;
- void Look(float mouseDx, float mouseDy);
- void Move(float moveF, float moveL);
- Matrix4 WorldToCam() const;
- Matrix4 CamToWorld() const;
- Vector3 CamOffset() const;
- private:
- float cam_rx;
- float cam_ry;
- float bob_mag;
- float bob_phi;
- bool onGround;
- };
- #include "Portal.h"
- #include "Engine.h"
- #include <cassert>
- #include <iostream>
- Portal::Portal() : front(this), back(this) {
- mesh = AquireMesh("double_quad.obj");
- shader = AquireShader("portal");
- errShader = AquireShader("pink");
- }
- void Portal::Draw(const Camera& cam, GLuint curFBO) {
- assert(euler.x == 0.0f);
- assert(euler.z == 0.0f);
- //Draw pink to indicate end of render chain
- if (GH_REC_LEVEL <= 0) {
- DrawPink(cam);
- return;
- }
- //Find normal relative to camera
- Vector3 normal = Forward();
- const Vector3 camPos = cam.worldView.Inverse().Translation();
- const bool frontDirection = (camPos - pos).Dot(normal) > 0;
- const Warp* warp = (frontDirection ? &front : &back);
- if (frontDirection) {
- normal = -normal;
- }
- //Extra clipping to prevent artifacts
- const float extra_clip = GH_MIN(GH_ENGINE->NearestPortalDist() * 0.5f, 0.1f);
- //Create new portal camera
- Camera portalCam = cam;
- portalCam.ClipOblique(pos - normal*extra_clip, -normal);
- portalCam.worldView *= warp->delta;
- portalCam.width = GH_FBO_SIZE;
- portalCam.height = GH_FBO_SIZE;
- //Render portal's view from new camera
- frameBuf[GH_REC_LEVEL - 1].Render(portalCam, curFBO, warp->toPortal);
- cam.UseViewport();
- //Now we can render the portal texture to the screen
- const Matrix4 mv = LocalToWorld();
- const Matrix4 mvp = cam.Matrix() * mv;
- shader->Use();
- frameBuf[GH_REC_LEVEL - 1].Use();
- shader->SetMVP(mvp.m, mv.m);
- mesh->Draw();
- }
- void Portal::DrawPink(const Camera& cam) {
- const Matrix4 mv = LocalToWorld();
- const Matrix4 mvp = cam.Matrix() * mv;
- errShader->Use();
- errShader->SetMVP(mvp.m, mv.m);
- mesh->Draw();
- }
- Vector3 Portal::GetBump(const Vector3& a) const {
- const Vector3 n = Forward();
- return n * ((a - pos).Dot(n) > 0 ? 1.0f : -1.0f);
- }
- const Portal::Warp* Portal::Intersects(const Vector3& a, const Vector3& b, const Vector3& bump) const {
- const Vector3 n = Forward();
- const Vector3 p = pos + bump;
- const float da = n.Dot(a - p);
- const float db = n.Dot(b - p);
- if (da * db > 0.0f) {
- return nullptr;
- }
- const Matrix4 m = LocalToWorld();
- const Vector3 d = a + (b - a) * (da / (da - db)) - p;
- const Vector3 x = (m * Vector4(1, 0, 0, 0)).XYZ();
- if (std::abs(d.Dot(x)) >= x.Dot(x)) {
- return nullptr;
- }
- const Vector3 y = (m * Vector4(0, 1, 0, 0)).XYZ();
- if (std::abs(d.Dot(y)) >= y.Dot(y)) {
- return nullptr;
- }
- return (da > 0.0f ? &front : &back);
- }
- float Portal::DistTo(const Vector3& pt) const {
- //Get world delta
- const Matrix4 localToWorld = LocalToWorld();
- const Vector3 v = pt - localToWorld.Translation();
- //Get axes
- const Vector3 x = localToWorld.XAxis();
- const Vector3 y = localToWorld.YAxis();
- //Find closest point
- const float px = GH_CLAMP(v.Dot(x) / x.MagSq(), -1.0f, 1.0f);
- const float py = GH_CLAMP(v.Dot(y) / y.MagSq(), -1.0f, 1.0f);
- const Vector3 closest = x*px + y*py;
- //Calculate distance to closest point
- return (v - closest).Mag();
- }
- void Portal::Connect(std::shared_ptr<Portal>& a, std::shared_ptr<Portal>& b) {
- Connect(a->front, b->back);
- Connect(b->front, a->back);
- }
- void Portal::Connect(Warp& a, Warp& b) {
- a.toPortal = b.fromPortal;
- b.toPortal = a.fromPortal;
- a.delta = a.fromPortal->LocalToWorld() * b.fromPortal->WorldToLocal();
- b.delta = b.fromPortal->LocalToWorld() * a.fromPortal->WorldToLocal();
- a.deltaInv = b.delta;
- b.deltaInv = a.delta;
- }
- #pragma once
- #include "GameHeader.h"
- #include "Object.h"
- #include "FrameBuffer.h"
- #include "Mesh.h"
- #include "Resources.h"
- #include "Shader.h"
- #include <memory>
- class Portal : public Object {
- public:
- //Subclass that represents a warp
- struct Warp {
- Warp(const Portal* fromPortal) : fromPortal(fromPortal), toPortal(nullptr) {
- delta.MakeIdentity();
- deltaInv.MakeIdentity();
- }
- Matrix4 delta;
- Matrix4 deltaInv;
- const Portal* fromPortal;
- const Portal* toPortal;
- };
- Portal();
- virtual ~Portal() {}
- virtual void Draw(const Camera& cam, GLuint curFBO) override;
- void DrawPink(const Camera& cam);
- Vector3 GetBump(const Vector3& a) const;
- const Warp* Intersects(const Vector3& a, const Vector3& b, const Vector3& bump) const;
- float DistTo(const Vector3& pt) const;
- static void Connect(std::shared_ptr<Portal>& a, std::shared_ptr<Portal>& b);
- static void Connect(Warp& a, Warp& b);
- Warp front;
- Warp back;
- private:
- std::shared_ptr<Shader> errShader;
- FrameBuffer frameBuf[GH_MAX_RECURSION <= 1 ? 1 : GH_MAX_RECURSION - 1];
- };
- typedef std::vector<std::shared_ptr<Portal>> PPortalVec;
- #include "Resources.h"
- #include <unordered_map>
- std::shared_ptr<Mesh> AquireMesh(const char* name) {
- static std::unordered_map<std::string, std::weak_ptr<Mesh>> map;
- std::weak_ptr<Mesh>& mesh = map[std::string(name)];
- if (mesh.expired()) {
- std::shared_ptr<Mesh> newMesh(new Mesh(name));
- mesh = newMesh;
- return newMesh;
- } else {
- return mesh.lock();
- }
- }
- std::shared_ptr<Shader> AquireShader(const char* name) {
- static std::unordered_map<std::string, std::weak_ptr<Shader>> map;
- std::weak_ptr<Shader>& shader = map[std::string(name)];
- if (shader.expired()) {
- std::shared_ptr<Shader> newShader(new Shader(name));
- shader = newShader;
- return newShader;
- } else {
- return shader.lock();
- }
- }
- std::shared_ptr<Texture> AquireTexture(const char* name, int rows, int cols) {
- static std::unordered_map<std::string, std::weak_ptr<Texture>> map;
- std::weak_ptr<Texture>& tex = map[std::string(name)];
- if (tex.expired()) {
- std::shared_ptr<Texture> newTex(new Texture(name, rows, cols));
- tex = newTex;
- return newTex;
- } else {
- return tex.lock();
- }
- }
- #pragma once
- #include "Mesh.h"
- #include "Texture.h"
- #include "Shader.h"
- #include <memory>
- std::shared_ptr<Mesh> AquireMesh(const char* name);
- std::shared_ptr<Shader> AquireShader(const char* name);
- std::shared_ptr<Texture> AquireTexture(const char* name, int rows=1, int cols=1);
- #pragma once
- #include "Object.h"
- #include "Portal.h"
- #include "Player.h"
- class Scene {
- public:
- virtual void Load(PObjectVec& objs, PPortalVec& portals, Player& player)=0;
- virtual void Unload() {};
- };
- #include "Shader.h"
- #include <fstream>
- #include <sstream>
- Shader::Shader(const char* name) {
- //Get the file paths
- const std::string vert = "Shaders/" + std::string(name) + ".vert";
- const std::string frag = "Shaders/" + std::string(name) + ".frag";
- //Load the shaders from disk
- vertId = LoadShader(vert.c_str(), GL_VERTEX_SHADER);
- fragId = LoadShader(frag.c_str(), GL_FRAGMENT_SHADER);
- //Create the program
- progId = glCreateProgram();
- glAttachShader(progId, vertId);
- glAttachShader(progId, fragId);
- //Bind variables
- for (size_t i = 0; i < attribs.size(); ++i) {
- glBindAttribLocation(progId, (GLuint)i, attribs[i].c_str());
- }
- //Link the program
- glLinkProgram(progId);
- //Check for linking errors
- GLint isLinked;
- glGetProgramiv(progId, GL_LINK_STATUS, &isLinked);
- if (!isLinked) {
- GLint logLength;
- glGetProgramiv(progId, GL_INFO_LOG_LENGTH, &logLength);
- std::vector<GLchar> log;
- log.resize(logLength);
- glGetProgramInfoLog(progId, logLength, &logLength, log.data());
- std::ofstream fout(std::string(vert) + ".link.log");
- fout.write(log.data(), logLength);
- progId = 0;
- return;
- }
- //Get global variable locations
- mvpId = glGetUniformLocation(progId, "mvp");
- mvId = glGetUniformLocation(progId, "mv");
- }
- Shader::~Shader() {
- glDetachShader(progId, vertId);
- glDetachShader(progId, fragId);
- glDeleteProgram(progId);
- glDeleteShader(vertId);
- glDeleteShader(fragId);
- }
- void Shader::Use() {
- glUseProgram(progId);
- }
- GLuint Shader::LoadShader(const char* fname, GLenum type) {
- //Read shader source from disk
- std::ifstream fin(fname);
- std::stringstream buff;
- buff << fin.rdbuf();
- const std::string str = buff.str();
- const char* source = str.c_str();
- //Create and compile shader
- const GLuint id = glCreateShader(type);
- glShaderSource(id, 1, (const GLchar**)&source, 0);
- glCompileShader(id);
- //Check to make sure there were no errors
- GLint isCompiled = 0;
- glGetShaderiv(id, GL_COMPILE_STATUS, &isCompiled);
- if (!isCompiled) {
- GLint logLength;
- glGetShaderiv(id, GL_INFO_LOG_LENGTH, &logLength);
- std::vector<GLchar> log;
- log.resize(logLength);
- glGetShaderInfoLog(id, logLength, &logLength, log.data());
- std::ofstream fout(std::string(fname) + ".log");
- fout.write(log.data(), logLength);
- return 0;
- }
- //Save variable bindings
- if (type == GL_VERTEX_SHADER) {
- size_t ix = 0;
- while (true) {
- ix = str.find("\nin ", ix);
- if (ix == std::string::npos) {
- break;
- }
- ix = str.find(";", ix);
- size_t start_ix = ix;
- while (str[--start_ix] != ' ');
- attribs.push_back(str.substr(start_ix + 1, ix - start_ix - 1));
- }
- }
- //Return the shader id
- return id;
- }
- void Shader::SetMVP(const float* mvp, const float* mv) {
- if (mvp) glUniformMatrix4fv(mvpId, 1, GL_TRUE, mvp);
- if (mv) glUniformMatrix4fv(mvId, 1, GL_TRUE, mv);
- }
- #pragma once
- #include <GL/glew.h>
- #include <vector>
- class Shader {
- public:
- Shader(const char* name);
- ~Shader();
- void Use();
- void SetMVP(const float* mvp, const float* mv);
- private:
- GLuint LoadShader(const char* fname, GLenum type);
- std::vector<std::string> attribs;
- GLuint vertId;
- GLuint fragId;
- GLuint progId;
- GLuint mvpId;
- GLuint mvId;
- };
- #pragma once
- #include "Resources.h"
- #include "Vector.h"
- class Sky {
- public:
- Sky() {
- mesh = AquireMesh("quad.obj");
- shader = AquireShader("sky");
- }
- void Draw(const Camera& cam) {
- glDepthMask(GL_FALSE);
- const Matrix4 mvp = cam.projection.Inverse();
- const Matrix4 mv = cam.worldView.Inverse();
- shader->Use();
- shader->SetMVP(mvp.m, mv.m);
- mesh->Draw();
- glDepthMask(GL_TRUE);
- }
- private:
- std::shared_ptr<Mesh> mesh;
- std::shared_ptr<Shader> shader;
- };
- #pragma once
- #include "Vector.h"
- #include <cassert>
- class Sphere {
- public:
- Sphere(float r=1.0f) : center(0.0f), radius(r) {}
- Sphere(const Vector3& pos, float r) : center(pos), radius(r) {}
- //Transformations to and frpom sphere coordinates
- Matrix4 UnitToLocal() const {
- assert(radius > 0.0f);
- return Matrix4::Trans(center) * Matrix4::Scale(radius);
- }
- Matrix4 LocalToUnit() const {
- assert(radius > 0.0f);
- return Matrix4::Scale(1.0f / radius) * Matrix4::Trans(-center);
- }
- Vector3 center;
- float radius;
- };
- #pragma once
- #include "Object.h"
- #include "Resources.h"
- class Statue : public Object {
- public:
- Statue(const char* model) {
- mesh = AquireMesh(model);
- shader = AquireShader("texture");
- texture = AquireTexture("gold.bmp");
- }
- virtual ~Statue() {}
- };
- #include "Texture.h"
- #include <fstream>
- #include <cassert>
- Texture::Texture(const char* fname, int rows, int cols) {
- //Check if this is a 3D texture
- assert(rows >= 1 && cols >= 1);
- is3D = (rows > 1 || cols > 1);
- //Open the bitmap
- std::ifstream fin(std::string("Textures/") + fname, std::ios::in | std::ios::binary);
- if (!fin) {
- texId = 0;
- return;
- }
- //Read the bitmap
- char input[54];
- fin.read(input, 54);
- const GLsizei width = *reinterpret_cast<int32_t*>(&input[18]);
- const GLsizei height = *reinterpret_cast<int32_t*>(&input[22]);
- assert(width % cols == 0);
- assert(height % rows == 0);
- const int block_w = width / cols;
- const int block_h = height / rows;
- uint8_t* img = new uint8_t[width * height * 3];
- for (int y = height; y--> 0;) {
- const int row = y / block_h;
- const int ty = y % block_h;
- for (int x = 0; x < width; x++) {
- const int col = x / block_w;
- const int tx = x % block_w;
- uint8_t* ptr = img + ((row*cols + col)*(block_w * block_h) + ty*block_w + tx)*3;
- fin.read(reinterpret_cast<char*>(ptr), 3);
- }
- const int padding = (width * 3) % 4;
- if (padding) {
- char junk[3];
- fin.read(junk, 4 - padding);
- }
- }
- //Load texture into video memory
- glGenTextures(1, &texId);
- if (is3D) {
- glBindTexture(GL_TEXTURE_2D_ARRAY, texId);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_GENERATE_MIPMAP, GL_TRUE);
- glGenerateMipmap(GL_TEXTURE_2D);
- glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB8, width/rows, height/cols, rows*cols, 0, GL_BGR, GL_UNSIGNED_BYTE, img);
- } else {
- glBindTexture(GL_TEXTURE_2D, texId);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, img);
- }
- //Clenup
- delete[] img;
- }
- void Texture::Use() {
- if (is3D) {
- glBindTexture(GL_TEXTURE_2D_ARRAY, texId);
- } else {
- glBindTexture(GL_TEXTURE_2D, texId);
- }
- }
- #pragma once
- #include <GL/glew.h>
- class Texture {
- public:
- Texture(const char* fname, int rows, int cols);
- void Use();
- private:
- GLuint texId;
- bool is3D;
- };
- #pragma once
- #include <Windows.h>
- class Timer {
- public:
- Timer() {
- QueryPerformanceFrequency(&frequency);
- }
- void Start() {
- QueryPerformanceCounter(&t1);
- }
- float Stop() {
- QueryPerformanceCounter(&t2);
- return float(t2.QuadPart - t1.QuadPart) / frequency.QuadPart;
- }
- int64_t GetTicks() {
- QueryPerformanceCounter(&t2);
- return t2.QuadPart;
- }
- int64_t SecondsToTicks(float s) {
- return int64_t(float(frequency.QuadPart) * s);
- }
- float StopStart() {
- const float result = Stop();
- t1 = t2;
- return result;
- }
- private:
- LARGE_INTEGER frequency; // ticks per second
- LARGE_INTEGER t1, t2; // ticks
- };
- #pragma once
- #include "Object.h"
- class Tunnel : public Object {
- public:
- enum Type {
- NORMAL = 0,
- SCALE = 1,
- SLOPE = 2,
- };
- Tunnel(Type type) : type(type) {
- if (type == SCALE) {
- mesh = AquireMesh("tunnel_scale.obj");
- } else if (type == SLOPE) {
- mesh = AquireMesh("tunnel_slope.obj");
- } else {
- mesh = AquireMesh("tunnel.obj");
- }
- shader = AquireShader("texture");
- texture = AquireTexture("checker_gray.bmp");
- }
- virtual ~Tunnel() {}
- void SetDoor1(Object& portal) const {
- portal.pos = LocalToWorld().MulPoint(Vector3(0, 1, 1));
- portal.euler = euler;
- portal.scale = Vector3(0.6f, 0.999f, 1) * scale.x;
- }
- void SetDoor2(Object& portal) const {
- portal.euler = euler;
- if (type == SCALE) {
- portal.pos = LocalToWorld().MulPoint(Vector3(0, 0.5f, -1));
- portal.scale = Vector3(0.3f, 0.499f, 0.5f) * scale.x;
- } else if (type == SLOPE) {
- portal.pos = LocalToWorld().MulPoint(Vector3(0, -1, -1));
- portal.scale = Vector3(0.6f, 0.999f, 1) * scale.x;
- } else {
- portal.pos = LocalToWorld().MulPoint(Vector3(0, 1, -1));
- portal.scale = Vector3(0.6f, 0.999f, 1) * scale.x;
- }
- }
- private:
- Type type;
- };
- #pragma once
- #include <cmath>
- #include <cfloat>
- #include <memory>
- #include <iostream>
- #include <cassert>
- class Vector3 {
- public:
- //Constructors
- Vector3() {}
- explicit Vector3(float b) : x(b), y(b), z(b) {}
- explicit Vector3(const float* b) : x(b[0]), y(b[1]), z(b[2]) {}
- explicit Vector3(float x, float y, float z) : x(x), y(y), z(z) {}
- //General
- inline static Vector3 Zero() { return Vector3(0.0f); }
- inline static Vector3 Ones() { return Vector3(1.0f); }
- inline static Vector3 UnitX() { return Vector3(1, 0, 0); }
- inline static Vector3 UnitY() { return Vector3(0, 1, 0); }
- inline static Vector3 UnitZ() { return Vector3(0, 0, 1); }
- //Setters
- inline void Set(float _x, float _y, float _z) { x = _x; y = _y; z = _z; }
- inline void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; }
- inline void SetOnes() { x = 1.0f; y = 1.0f; z = 1.0f; }
- inline void SetUnitX() { x = 1.0f; y = 0.0f; z = 0.0f; }
- inline void SetUnitY() { x = 0.0f; y = 1.0f; z = 0.0f; }
- inline void SetUnitZ() { x = 0.0f; y = 0.0f; z = 1.0f; }
- //Basic operatios
- inline Vector3 operator+(float b) const {
- return Vector3(x + b, y + b, z + b);
- }
- inline Vector3 operator-(float b) const {
- return Vector3(x - b, y - b, z - b);
- }
- inline Vector3 operator*(float b) const {
- return Vector3(x * b, y * b, z * b);
- }
- inline Vector3 operator/(float b) const {
- return Vector3(x / b, y / b, z / b);
- }
- inline Vector3 operator+(const Vector3& b) const {
- return Vector3(x + b.x, y + b.y, z + b.z);
- }
- inline Vector3 operator-(const Vector3& b) const {
- return Vector3(x - b.x, y - b.y, z - b.z);
- }
- inline Vector3 operator*(const Vector3& b) const {
- return Vector3(x * b.x, y * b.y, z * b.z);
- }
- inline Vector3 operator/(const Vector3& b) const {
- return Vector3(x / b.x, y / b.y, z / b.z);
- }
- inline void operator+=(float b) {
- x += b; y += b; z += b;
- }
- inline void operator-=(float b) {
- x -= b; y -= b; z -= b;
- }
- inline void operator*=(float b) {
- x *= b; y *= b; z *= b;
- }
- inline void operator/=(float b) {
- x /= b; y /= b; z /= b;
- }
- inline void operator+=(const Vector3& b) {
- x += b.x; y += b.y; z += b.z;
- }
- inline void operator-=(const Vector3& b) {
- x -= b.x; y -= b.y; z -= b.z;
- }
- inline void operator*=(const Vector3& b) {
- x *= b.x; y *= b.y; z *= b.z;
- }
- inline void operator/=(const Vector3& b) {
- x /= b.x; y /= b.y; z /= b.z;
- }
- inline Vector3 operator-() const {
- return Vector3(-x, -y, -z);
- }
- //Vector algebra
- inline float Dot(const Vector3& b) const {
- return x*b.x + y*b.y + z*b.z;
- }
- inline Vector3 Cross(const Vector3& b) const {
- return Vector3(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x);
- }
- inline float MagSq() const {
- return x*x + y*y + z*z;
- }
- inline float Mag() const {
- return std::sqrt(MagSq());
- }
- //Normalization
- inline void Normalize() {
- (*this) /= Mag();
- }
- inline void NormalizeSafe() {
- (*this) /= (Mag() + FLT_EPSILON);
- }
- inline Vector3 Normalized() const {
- return (*this) / Mag();
- }
- inline Vector3 NormalizedSafe() const {
- return (*this) / (Mag() + FLT_EPSILON);
- }
- inline float Angle(const Vector3& b) const {
- return std::acos(Normalized().Dot(b.Normalized()));
- }
- inline float AngleSafe(const Vector3& b) const {
- return std::acos(NormalizedSafe().Dot(b.NormalizedSafe()));
- }
- inline void ClipMag(float m) {
- assert(m > 0.0f);
- const float r = MagSq() / (m * m);
- if (r > 1.0f) {
- (*this) /= std::sqrt(r);
- }
- }
- //Other
- inline bool IsNDC() const {
- return (x > -1.0f && x < 1.0f && y > -1.0f && y < 1.0f && z > -1.0f && z < 1.0f);
- }
- //Components
- float x, y, z;
- };
- inline Vector3 operator/(float b, const Vector3& v) {
- return Vector3(b / v.x, b / v.y, b / v.z);
- }
- inline void operator/=(float b, Vector3& v) {
- v.x = b / v.x; v.y = b / v.y; v.z = b / v.z;
- }
- class Vector4 {
- public:
- Vector4() {}
- explicit Vector4(float b) : x(b), y(b), z(b), w(b) {}
- explicit Vector4(const Vector3& xyz, float w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
- explicit Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
- inline Vector3 XYZ() const { return Vector3(x, y, z); }
- inline Vector3 XYZNormalized() const { return Vector3(x, y, z).Normalized(); }
- inline Vector3 Homogenized() const { return Vector3(x/w, y/w, z/w); }
- inline Vector4 operator*(float b) const {
- return Vector4(x * b, y * b, z * b, w * b);
- }
- inline Vector4 operator/(float b) const {
- return Vector4(x / b, y / b, z / b, w / b);
- }
- inline void operator*=(float b) {
- x *= b; y *= b; z *= b; w *= b;
- }
- inline void operator/=(float b) {
- x /= b; y /= b; z /= b; w /= b;
- }
- inline float Dot(const Vector4& b) const { return x*b.x + y*b.y + z*b.z + w*b.w; }
- //Components
- float x, y, z, w;
- };
- class Matrix4 {
- public:
- //Constructors
- Matrix4() {}
- explicit Matrix4(float b) { Fill(b); }
- //General
- inline void Fill(float b) {
- std::fill(m, m + 16, b);
- }
- inline void MakeZero() {
- Fill(0.0f);
- }
- inline void MakeIdentity() {
- m[0] = 1.0f; m[1] = 0.0f; m[2] = 0.0f; m[3] = 0.0f;
- m[4] = 0.0f; m[5] = 1.0f; m[6] = 0.0f; m[7] = 0.0f;
- m[8] = 0.0f; m[9] = 0.0f; m[10] = 1.0f; m[11] = 0.0f;
- m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f;
- }
- inline void MakeRotX(float a) {
- m[0] = 1.0f; m[1] = 0.0f; m[2] = 0.0f; m[3] = 0.0f;
- m[4] = 0.0f; m[5] = std::cos(a); m[6] = -std::sin(a); m[7] = 0.0f;
- m[8] = 0.0f; m[9] = std::sin(a); m[10] = std::cos(a); m[11] = 0.0f;
- m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f;
- }
- inline void MakeRotY(float a) {
- m[0] = std::cos(a); m[1] = 0.0f; m[2] = std::sin(a); m[3] = 0.0f;
- m[4] = 0.0f; m[5] = 1.0f; m[6] = 0.0f; m[7] = 0.0f;
- m[8] = -std::sin(a); m[9] = 0.0f; m[10] = std::cos(a); m[11] = 0.0f;
- m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f;
- }
- inline void MakeRotZ(float a) {
- m[0] = std::cos(a); m[1] = -std::sin(a); m[2] = 0.0f; m[3] = 0.0f;
- m[4] = std::sin(a); m[5] = std::cos(a); m[6] = 0.0f; m[7] = 0.0f;
- m[8] = 0.0f; m[9] = 0.0f; m[10] = 1.0f; m[11] = 0.0f;
- m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f;
- }
- inline void MakeTrans(const Vector3& t) {
- m[0] = 1.0f; m[1] = 0.0f; m[2] = 0.0f; m[3] = t.x;
- m[4] = 0.0f; m[5] = 1.0f; m[6] = 0.0f; m[7] = t.y;
- m[8] = 0.0f; m[9] = 0.0f; m[10] = 1.0f; m[11] = t.z;
- m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f;
- }
- inline void MakeScale(const Vector3& s) {
- m[0] = s.x; m[1] = 0.0f; m[2] = 0.0f; m[3] = 0.0f;
- m[4] = 0.0f; m[5] = s.y; m[6] = 0.0f; m[7] = 0.0f;
- m[8] = 0.0f; m[9] = 0.0f; m[10] = s.z; m[11] = 0.0f;
- m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f;
- }
- //Statics
- inline static Matrix4 Zero() { Matrix4 m; m.MakeZero(); return m; }
- inline static Matrix4 Identity() { Matrix4 m; m.MakeIdentity(); return m; }
- inline static Matrix4 RotX(float a) { Matrix4 m; m.MakeRotX(a); return m; }
- inline static Matrix4 RotY(float a) { Matrix4 m; m.MakeRotY(a); return m; }
- inline static Matrix4 RotZ(float a) { Matrix4 m; m.MakeRotZ(a); return m; }
- inline static Matrix4 Trans(const Vector3& t) { Matrix4 m; m.MakeTrans(t); return m; }
- inline static Matrix4 Scale(float s) { Matrix4 m; m.MakeScale(Vector3(s)); return m; }
- inline static Matrix4 Scale(const Vector3& s) { Matrix4 m; m.MakeScale(s); return m; }
- //Some getters
- inline Vector3 XAxis() const {
- return Vector3(m[0], m[4], m[8]);
- }
- inline Vector3 YAxis() const {
- return Vector3(m[1], m[5], m[9]);
- }
- inline Vector3 ZAxis() const {
- return Vector3(m[2], m[6], m[10]);
- }
- inline Vector3 Translation() const {
- return Vector3(m[3], m[7], m[11]);
- }
- inline Vector3 Scale() const {
- return Vector3(m[0], m[5], m[10]);
- }
- //Setters
- inline void SetTranslation(const Vector3& t) {
- m[3] = t.x;
- m[7] = t.y;
- m[11] = t.z;
- }
- inline void SetXAxis(const Vector3& t) {
- m[0] = t.x;
- m[4] = t.y;
- m[8] = t.z;
- }
- inline void SetYAxis(const Vector3& t) {
- m[1] = t.x;
- m[5] = t.y;
- m[9] = t.z;
- }
- inline void SetZAxis(const Vector3& t) {
- m[2] = t.x;
- m[6] = t.y;
- m[10] = t.z;
- }
- inline void SetScale(const Vector3& s) {
- m[0] = s.x;
- m[5] = s.y;
- m[10] = s.z;
- }
- //Transformations
- inline Matrix4 Transposed() const {
- Matrix4 out;
- out.m[0] = m[0]; out.m[1] = m[4]; out.m[2] = m[8]; out.m[3] = m[12];
- out.m[4] = m[1]; out.m[5] = m[5]; out.m[6] = m[9]; out.m[7] = m[13];
- out.m[8] = m[2]; out.m[9] = m[6]; out.m[10] = m[10]; out.m[11] = m[14];
- out.m[12] = m[3]; out.m[13] = m[7]; out.m[14] = m[11]; out.m[15] = m[15];
- return out;
- }
- inline void Translate(const Vector3& t) {
- m[3] += t.x;
- m[7] += t.y;
- m[11] += t.z;
- }
- inline void Stretch(const Vector3& s) {
- m[0] *= s.x;
- m[5] *= s.y;
- m[10] *= s.z;
- }
- //Basic operatios
- inline Matrix4 operator+(const Matrix4& b) const {
- Matrix4 out;
- for (int i = 0; i < 16; ++i) { out.m[i] = m[i] + b.m[i]; }
- return out;
- }
- inline Matrix4 operator-(const Matrix4& b) const {
- Matrix4 out;
- for (int i = 0; i < 16; ++i) { out.m[i] = m[i] - b.m[i]; }
- return out;
- }
- inline void operator+=(const Matrix4& b) {
- for (int i = 0; i < 16; ++i) { m[i] += b.m[i]; }
- }
- inline void operator-=(const Matrix4& b) {
- for (int i = 0; i < 16; ++i) { m[i] -= b.m[i]; }
- }
- inline void operator*=(float b) {
- for (int i = 0; i < 16; ++i) { m[i] *= b; }
- }
- inline void operator/=(float b) {
- operator*=(1.0f / b);
- }
- //Multiplication
- Matrix4 operator*(const Matrix4& b) const {
- Matrix4 out;
- out.m[0] = b.m[0]*m[0] + b.m[4]*m[1] + b.m[8] *m[2] + b.m[12]*m[3];
- out.m[1] = b.m[1]*m[0] + b.m[5]*m[1] + b.m[9] *m[2] + b.m[13]*m[3];
- out.m[2] = b.m[2]*m[0] + b.m[6]*m[1] + b.m[10]*m[2] + b.m[14]*m[3];
- out.m[3] = b.m[3]*m[0] + b.m[7]*m[1] + b.m[11]*m[2] + b.m[15]*m[3];
- out.m[4] = b.m[0]*m[4] + b.m[4]*m[5] + b.m[8] *m[6] + b.m[12]*m[7];
- out.m[5] = b.m[1]*m[4] + b.m[5]*m[5] + b.m[9] *m[6] + b.m[13]*m[7];
- out.m[6] = b.m[2]*m[4] + b.m[6]*m[5] + b.m[10]*m[6] + b.m[14]*m[7];
- out.m[7] = b.m[3]*m[4] + b.m[7]*m[5] + b.m[11]*m[6] + b.m[15]*m[7];
- out.m[8] = b.m[0]*m[8] + b.m[4]*m[9] + b.m[8] *m[10] + b.m[12]*m[11];
- out.m[9] = b.m[1]*m[8] + b.m[5]*m[9] + b.m[9] *m[10] + b.m[13]*m[11];
- out.m[10] = b.m[2]*m[8] + b.m[6]*m[9] + b.m[10]*m[10] + b.m[14]*m[11];
- out.m[11] = b.m[3]*m[8] + b.m[7]*m[9] + b.m[11]*m[10] + b.m[15]*m[11];
- out.m[12] = b.m[0]*m[12] + b.m[4]*m[13] + b.m[8] *m[14] + b.m[12]*m[15];
- out.m[13] = b.m[1]*m[12] + b.m[5]*m[13] + b.m[9] *m[14] + b.m[13]*m[15];
- out.m[14] = b.m[2]*m[12] + b.m[6]*m[13] + b.m[10]*m[14] + b.m[14]*m[15];
- out.m[15] = b.m[3]*m[12] + b.m[7]*m[13] + b.m[11]*m[14] + b.m[15]*m[15];
- return out;
- }
- void operator*=(const Matrix4& b) {
- (*this) = operator*(b);
- }
- Vector4 operator*(const Vector4& b) const {
- return Vector4(
- m[0]*b.x + m[1]*b.y + m[2]*b.z + m[3]*b.w,
- m[4]*b.x + m[5]*b.y + m[6]*b.z + m[7]*b.w,
- m[8]*b.x + m[9]*b.y + m[10]*b.z + m[11]*b.w,
- m[12]*b.x + m[13]*b.y + m[14]*b.z + m[15]*b.w
- );
- }
- Vector3 MulPoint(const Vector3& b) const {
- const Vector3 p(
- m[0] * b.x + m[1] * b.y + m[2] * b.z + m[3],
- m[4] * b.x + m[5] * b.y + m[6] * b.z + m[7],
- m[8] * b.x + m[9] * b.y + m[10] * b.z + m[11]
- );
- const float w = m[12] * b.x + m[13] * b.y + m[14] * b.z + m[15];
- return p / w;
- }
- Vector3 MulDirection(const Vector3& b) const {
- return Vector3(
- m[0] * b.x + m[1] * b.y + m[2] * b.z,
- m[4] * b.x + m[5] * b.y + m[6] * b.z,
- m[8] * b.x + m[9] * b.y + m[10] * b.z
- );
- }
- //Inverse
- Matrix4 Inverse() const {
- Matrix4 inv;
- inv.m[0] = m[5] * m[10] * m[15] -
- m[5] * m[11] * m[14] -
- m[9] * m[6] * m[15] +
- m[9] * m[7] * m[14] +
- m[13] * m[6] * m[11] -
- m[13] * m[7] * m[10];
- inv.m[4] = -m[4] * m[10] * m[15] +
- m[4] * m[11] * m[14] +
- m[8] * m[6] * m[15] -
- m[8] * m[7] * m[14] -
- m[12] * m[6] * m[11] +
- m[12] * m[7] * m[10];
- inv.m[8] = m[4] * m[9] * m[15] -
- m[4] * m[11] * m[13] -
- m[8] * m[5] * m[15] +
- m[8] * m[7] * m[13] +
- m[12] * m[5] * m[11] -
- m[12] * m[7] * m[9];
- inv.m[12] = -m[4] * m[9] * m[14] +
- m[4] * m[10] * m[13] +
- m[8] * m[5] * m[14] -
- m[8] * m[6] * m[13] -
- m[12] * m[5] * m[10] +
- m[12] * m[6] * m[9];
- inv.m[1] = -m[1] * m[10] * m[15] +
- m[1] * m[11] * m[14] +
- m[9] * m[2] * m[15] -
- m[9] * m[3] * m[14] -
- m[13] * m[2] * m[11] +
- m[13] * m[3] * m[10];
- inv.m[5] = m[0] * m[10] * m[15] -
- m[0] * m[11] * m[14] -
- m[8] * m[2] * m[15] +
- m[8] * m[3] * m[14] +
- m[12] * m[2] * m[11] -
- m[12] * m[3] * m[10];
- inv.m[9] = -m[0] * m[9] * m[15] +
- m[0] * m[11] * m[13] +
- m[8] * m[1] * m[15] -
- m[8] * m[3] * m[13] -
- m[12] * m[1] * m[11] +
- m[12] * m[3] * m[9];
- inv.m[13] = m[0] * m[9] * m[14] -
- m[0] * m[10] * m[13] -
- m[8] * m[1] * m[14] +
- m[8] * m[2] * m[13] +
- m[12] * m[1] * m[10] -
- m[12] * m[2] * m[9];
- inv.m[2] = m[1] * m[6] * m[15] -
- m[1] * m[7] * m[14] -
- m[5] * m[2] * m[15] +
- m[5] * m[3] * m[14] +
- m[13] * m[2] * m[7] -
- m[13] * m[3] * m[6];
- inv.m[6] = -m[0] * m[6] * m[15] +
- m[0] * m[7] * m[14] +
- m[4] * m[2] * m[15] -
- m[4] * m[3] * m[14] -
- m[12] * m[2] * m[7] +
- m[12] * m[3] * m[6];
- inv.m[10] = m[0] * m[5] * m[15] -
- m[0] * m[7] * m[13] -
- m[4] * m[1] * m[15] +
- m[4] * m[3] * m[13] +
- m[12] * m[1] * m[7] -
- m[12] * m[3] * m[5];
- inv.m[14] = -m[0] * m[5] * m[14] +
- m[0] * m[6] * m[13] +
- m[4] * m[1] * m[14] -
- m[4] * m[2] * m[13] -
- m[12] * m[1] * m[6] +
- m[12] * m[2] * m[5];
- inv.m[3] = -m[1] * m[6] * m[11] +
- m[1] * m[7] * m[10] +
- m[5] * m[2] * m[11] -
- m[5] * m[3] * m[10] -
- m[9] * m[2] * m[7] +
- m[9] * m[3] * m[6];
- inv.m[7] = m[0] * m[6] * m[11] -
- m[0] * m[7] * m[10] -
- m[4] * m[2] * m[11] +
- m[4] * m[3] * m[10] +
- m[8] * m[2] * m[7] -
- m[8] * m[3] * m[6];
- inv.m[11] = -m[0] * m[5] * m[11] +
- m[0] * m[7] * m[9] +
- m[4] * m[1] * m[11] -
- m[4] * m[3] * m[9] -
- m[8] * m[1] * m[7] +
- m[8] * m[3] * m[5];
- inv.m[15] = m[0] * m[5] * m[10] -
- m[0] * m[6] * m[9] -
- m[4] * m[1] * m[10] +
- m[4] * m[2] * m[9] +
- m[8] * m[1] * m[6] -
- m[8] * m[2] * m[5];
- const float det = m[0] * inv.m[0] + m[1] * inv.m[4] + m[2] * inv.m[8] + m[3] * inv.m[12];
- inv /= det;
- return inv;
- }
- //Components
- float m[16];
- };
- //Debug printing
- inline std::ostream& operator<<(std::ostream& out, const Vector3& v) {
- out << v.x << ", " << v.y << ", " << v.z;
- return out;
- }
- inline std::ostream& operator<<(std::ostream& out, const Vector4& v) {
- out << v.x << ", " << v.y << ", " << v.z << ", " << v.w;
- return out;
- }
- inline std::ostream& operator<<(std::ostream& out, const Matrix4& m) {
- out << m.m[0] << ", " << m.m[1] << ", " << m.m[2] << ", " << m.m[3] << "\n";
- out << m.m[4] << ", " << m.m[5] << ", " << m.m[6] << ", " << m.m[7] << "\n";
- out << m.m[8] << ", " << m.m[9] << ", " << m.m[10] << ", " << m.m[11] << "\n";
- out << m.m[12] << ", " << m.m[13] << ", " << m.m[14] << ", " << m.m[15];
- return out;
- }
Add Comment
Please, Sign In to add comment