428 lines
10 KiB
C++
Executable File
428 lines
10 KiB
C++
Executable File
#include "TextureManager.h"
|
|
#include "ShaderManager.h"
|
|
#include "Renderer.h"
|
|
|
|
#include "Physics.h"
|
|
#include <string>
|
|
|
|
#include <windows.h>
|
|
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <iostream>
|
|
|
|
#include "Game.h"
|
|
|
|
namespace ZL
|
|
{
|
|
|
|
HGLRC hRC; //Render context
|
|
HWND Hwnd; //Main window handle
|
|
HDC hDC; //Device context
|
|
|
|
Renderer renderer;
|
|
|
|
GameState gs;
|
|
|
|
|
|
//There might be anything
|
|
const wchar_t CONST_WINDOW_CLASS_NAME[] = L"ZeptoLabClass";
|
|
|
|
const size_t CONST_TIMER_INTERVAL = 10;
|
|
|
|
const size_t CONST_MAX_TIME_INTERVAL = 1000;
|
|
|
|
bool ExitGameLoop = false;
|
|
|
|
//To calculate when to call Update
|
|
size_t NewTickCount;
|
|
size_t LastTickCount;
|
|
|
|
|
|
void DrawBackground()
|
|
{
|
|
renderer.PushMatrix();
|
|
|
|
renderer.LoadIdentity();
|
|
|
|
renderer.TranslateMatrix({ -gs.backgroundShift, 0.0f, 0.f });
|
|
|
|
glBindTexture(GL_TEXTURE_2D, GameObjects::backgroundTexturePtr->getTexID());
|
|
|
|
renderer.DrawVertexDataStruct(GameObjects::backgroundMesh);
|
|
|
|
renderer.PopMatrix();
|
|
}
|
|
|
|
void DrawBird()
|
|
{
|
|
renderer.PushMatrix();
|
|
|
|
renderer.LoadIdentity();
|
|
|
|
Vector2f birdScreenShift = gs.birdCurrentPos - Env::birdStartPos;
|
|
|
|
renderer.TranslateMatrix({ 200.f + birdScreenShift.v[0], Env::getActualClientHeight() * 0.5f + birdScreenShift.v[1], 0.f });
|
|
|
|
renderer.RotateMatrix(QuatFromRotateAroundZ(gs.birdAngle));
|
|
|
|
glBindTexture(GL_TEXTURE_2D, GameObjects::birdTexturePtr->getTexID());
|
|
|
|
renderer.DrawVertexDataStruct(GameObjects::birdMesh);
|
|
|
|
renderer.PopMatrix();
|
|
}
|
|
|
|
void DrawPipes()
|
|
{
|
|
for (auto& pipePair : gs.pipePairArr)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, GameObjects::pipeTexturePtr->getTexID());
|
|
|
|
|
|
//Draw bottom pipe:
|
|
renderer.PushMatrix();
|
|
|
|
renderer.LoadIdentity();
|
|
|
|
renderer.TranslateMatrix({ (pipePair.xPos), pipePair.bottomPipeVShift, 0.f });
|
|
|
|
renderer.DrawVertexDataStruct(GameObjects::pipeMesh);
|
|
|
|
|
|
//Draw top pipe:
|
|
|
|
renderer.LoadIdentity();
|
|
|
|
renderer.TranslateMatrix({ (pipePair.xPos), Env::getActualClientHeight() + pipePair.topPipeVShift, 0.f });
|
|
|
|
renderer.ScaleMatrix({ 1.f, -1.f, 1.f });
|
|
|
|
renderer.DrawVertexDataStruct(GameObjects::pipeMesh);
|
|
|
|
renderer.PopMatrix();
|
|
}
|
|
}
|
|
|
|
void DrawUi()
|
|
{
|
|
if (gs.isGameOver)
|
|
{
|
|
renderer.PushMatrix();
|
|
|
|
renderer.LoadIdentity();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, GameObjects::gameOverTexturePtr->getTexID());
|
|
|
|
renderer.DrawVertexDataStruct(GameObjects::gameOverMesh);
|
|
|
|
renderer.PopMatrix();
|
|
}
|
|
}
|
|
|
|
void DrawScene()
|
|
{
|
|
static const std::string defaultShaderName = "default";
|
|
static const std::string vPositionName = "vPosition";
|
|
static const std::string vTexCoordName = "vTexCoord";
|
|
static const std::string textureUniformName = "Texture";
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
|
CheckGlError();
|
|
|
|
glViewport(0, 0, Env::width, Env::height);
|
|
|
|
renderer.shaderManager.PushShader(defaultShaderName);
|
|
|
|
renderer.RenderUniform1i(textureUniformName, 0);
|
|
|
|
renderer.EnableVertexAttribArray(vPositionName);
|
|
renderer.EnableVertexAttribArray(vTexCoordName);
|
|
|
|
renderer.PushProjectionMatrix(static_cast<float>(Env::width), static_cast<float>(Env::height));
|
|
|
|
DrawBackground();
|
|
|
|
DrawPipes();
|
|
|
|
DrawBird();
|
|
|
|
DrawUi();
|
|
|
|
renderer.PopProjectionMatrix();
|
|
|
|
renderer.DisableVertexAttribArray(vTexCoordName);
|
|
renderer.DisableVertexAttribArray(vPositionName);
|
|
|
|
renderer.shaderManager.PopShader();
|
|
|
|
SwapBuffers(hDC);
|
|
}
|
|
|
|
|
|
|
|
void ProcessTickCount()
|
|
{
|
|
|
|
if (LastTickCount == 0)
|
|
{
|
|
LastTickCount = GetTickCount64();
|
|
return;
|
|
}
|
|
|
|
NewTickCount = GetTickCount64();
|
|
if (NewTickCount - LastTickCount > CONST_TIMER_INTERVAL)
|
|
{
|
|
if (NewTickCount - LastTickCount > CONST_MAX_TIME_INTERVAL)
|
|
{
|
|
gs.UpdateScene(CONST_MAX_TIME_INTERVAL); //Limit game update speed to FPS
|
|
}
|
|
else
|
|
{
|
|
gs.UpdateScene(NewTickCount - LastTickCount);
|
|
}
|
|
|
|
LastTickCount = NewTickCount;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
LRESULT WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static PAINTSTRUCT ps;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_CLOSE:
|
|
PostQuitMessage(0);
|
|
ExitGameLoop = true;
|
|
break;
|
|
case WM_PAINT:
|
|
|
|
DrawScene();
|
|
BeginPaint(hWnd, &ps);
|
|
EndPaint(hWnd, &ps);
|
|
|
|
ProcessTickCount();
|
|
break;
|
|
case WM_SIZE:
|
|
|
|
PostMessage(hWnd, WM_PAINT, 0, 0);
|
|
break;
|
|
case WM_LBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
|
|
if (gs.isGameOver)
|
|
{
|
|
gs.RestartGame();
|
|
}
|
|
else
|
|
{
|
|
gs.BirdJump();
|
|
}
|
|
break;
|
|
}
|
|
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
|
|
bool CreateOpenGLWindow(const wchar_t* title, int x, int y, int width, int height, HWND& hWnd, HDC& hDC, HGLRC& hRC)
|
|
{
|
|
int pf;
|
|
WNDCLASS wc;
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
static HINSTANCE hInstance = 0;
|
|
|
|
if (!hInstance)
|
|
{
|
|
hInstance = GetModuleHandle(NULL);
|
|
wc.style = CS_OWNDC;
|
|
wc.lpfnWndProc = (WNDPROC)WindowProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = CONST_WINDOW_CLASS_NAME;
|
|
|
|
if (!RegisterClass(&wc))
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
RECT r;
|
|
r.left = x;
|
|
r.right = x + width;
|
|
r.top = y;
|
|
r.bottom = y + height;
|
|
|
|
DWORD windowStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
|
|
|
AdjustWindowRect(&r, windowStyle, false);
|
|
|
|
Env::windowHeaderHeight = abs(r.top);
|
|
|
|
hWnd = CreateWindow(CONST_WINDOW_CLASS_NAME, title, windowStyle, 0, 0, r.right - r.left, r.bottom - r.top, NULL, NULL, hInstance, NULL);
|
|
|
|
if (hWnd == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
hDC = GetDC(hWnd);
|
|
|
|
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;
|
|
|
|
pf = ChoosePixelFormat(hDC, &pfd);
|
|
if (pf == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (SetPixelFormat(hDC, pf, &pfd) == FALSE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
hRC = wglCreateContext(hDC);
|
|
wglMakeCurrent(hDC, hRC);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void DestroyEngine()
|
|
{
|
|
|
|
wglMakeCurrent(NULL, NULL);
|
|
ReleaseDC(Hwnd, hDC);
|
|
wglDeleteContext(hRC);
|
|
DestroyWindow(Hwnd);
|
|
|
|
}
|
|
|
|
void MainLoop()
|
|
{
|
|
|
|
MSG msg;
|
|
|
|
ShowWindow(Hwnd, SW_SHOW);
|
|
UpdateWindow(Hwnd);
|
|
|
|
NewTickCount = GetTickCount64();
|
|
LastTickCount = NewTickCount;
|
|
|
|
while (!ExitGameLoop)
|
|
{
|
|
while (PeekMessage(&msg, Hwnd, 0, 0, PM_NOREMOVE))
|
|
{
|
|
if (GetMessage(&msg, Hwnd, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
else
|
|
{
|
|
ExitGameLoop = true;
|
|
}
|
|
}
|
|
DrawScene();
|
|
|
|
ProcessTickCount();
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
|
|
{
|
|
using namespace ZL;
|
|
|
|
try {
|
|
|
|
srand((unsigned)time(NULL));
|
|
|
|
constexpr int CONST_WIDTH = 1280;
|
|
constexpr int CONST_HEIGHT = 720;
|
|
|
|
Env::width = CONST_WIDTH;
|
|
Env::height = CONST_HEIGHT;
|
|
|
|
if (!CreateOpenGLWindow(L"ZeptoLabTest", 0, 0, Env::width, Env::height, Hwnd, hDC, hRC))
|
|
{
|
|
throw std::exception("Failed to create OpenGL Window!");
|
|
}
|
|
|
|
BindOpenGlFunctions();
|
|
|
|
//Load shaders:
|
|
renderer.shaderManager.AddShaderFromFiles("default", "./default.vertex", "./default.fragment");
|
|
|
|
//Load textures
|
|
GameObjects::birdTexturePtr = std::make_shared<Texture>(CreateTextureDataFromBmp32("./bird.bmp32"));
|
|
GameObjects::backgroundTexturePtr = std::make_shared<Texture>(CreateTextureDataFromBmp24("./background.bmp"));
|
|
GameObjects::pipeTexturePtr = std::make_shared<Texture>(CreateTextureDataFromBmp32("./pipe.bmp32"));
|
|
GameObjects::gameOverTexturePtr = std::make_shared<Texture>(CreateTextureDataFromBmp32("./game_over.bmp32"));
|
|
|
|
|
|
|
|
//Create bird mesh
|
|
GameObjects::birdMesh = CreateRect2D({ 0.f, 0.f }, { GameConsts::birdScale * GameObjects::birdTexturePtr->getWidth(), GameConsts::birdScale * GameObjects::birdTexturePtr->getHeight() }, 0);
|
|
|
|
float backgroundTextureScale = Env::height / static_cast<float>(GameObjects::backgroundTexturePtr->getHeight());
|
|
|
|
|
|
//Create pipe mesh
|
|
GameObjects::pipeMesh = CreateRect2D({ GameObjects::pipeTexturePtr->getWidth() * GameConsts::pipeScale * (-0.5f), Env::getActualClientHeight() * 0.5f + GameObjects::pipeTexturePtr->getHeight() * GameConsts::pipeScale * (-0.5f) }, { GameObjects::pipeTexturePtr->getWidth() * GameConsts::pipeScale * 0.5f, GameObjects::pipeTexturePtr->getHeight() * GameConsts::pipeScale * 0.5f }, 0);
|
|
|
|
|
|
//Create background mesh depending on screen size
|
|
|
|
Env::backgroundSectionWidth = GameObjects::backgroundTexturePtr->getWidth() * backgroundTextureScale;
|
|
|
|
GameObjects::backgroundMesh = CreateRectHorizontalSections2D({ GameObjects::backgroundTexturePtr->getWidth() * backgroundTextureScale * (0.5f), GameObjects::backgroundTexturePtr->getHeight() * backgroundTextureScale * (0.5f) }, { GameObjects::backgroundTexturePtr->getWidth() * backgroundTextureScale * 0.5f, GameObjects::backgroundTexturePtr->getHeight() * backgroundTextureScale * 0.5f }, 0, 2);
|
|
|
|
|
|
|
|
//Create Game Over UI mesh depending on screen size
|
|
|
|
float gameOverTextureScale = Env::height / static_cast<float>(GameObjects::gameOverTexturePtr->getHeight());
|
|
|
|
GameObjects::gameOverMesh = CreateRect2D({ GameObjects::gameOverTexturePtr->getWidth() * gameOverTextureScale * 0.5f, GameObjects::gameOverTexturePtr->getHeight() * gameOverTextureScale * 0.5f }, { GameObjects::gameOverTexturePtr->getWidth() * gameOverTextureScale * 0.5f, GameObjects::gameOverTexturePtr->getHeight() * gameOverTextureScale * 0.5f }, 0.1f);
|
|
|
|
|
|
|
|
//Set some game values
|
|
Env::birdStartPos = { Env::width * 0.2f, Env::getActualClientHeight() * 0.5f };
|
|
|
|
//Exact value depends on the bird look texture and must be calculated manually:
|
|
gs.birdEllipse.a = GameConsts::birdScale * 236.f;
|
|
gs.birdEllipse.b = GameConsts::birdScale * 160.f;
|
|
|
|
gs.RestartGame();
|
|
|
|
renderer.InitOpenGL();
|
|
|
|
MainLoop();
|
|
|
|
DestroyEngine();
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
std::cerr << "Oops: " << e.what() << std::endl;
|
|
}
|
|
|
|
return 0;
|
|
|
|
} |