1272 lines
41 KiB
C++
1272 lines
41 KiB
C++
#define _CRT_SECURE_NO_WARNINGS
|
||
#ifdef _MSC_VER // Check if MS Visual C compiler
|
||
# pragma comment(lib, "opengl32.lib") // Compiler-specific directive to avoid manually configuration
|
||
# pragma comment(lib, "glu32.lib") // Link libraries
|
||
#endif
|
||
#ifdef _MSC_VER
|
||
# ifndef _MBCS
|
||
# define _MBCS
|
||
# endif
|
||
# ifdef _UNICODE
|
||
# undef _UNICODE
|
||
# endif
|
||
# ifdef UNICODE
|
||
# undef UNICODE
|
||
# endif
|
||
#endif
|
||
// #define GLEW_STATIC
|
||
#include <windows.h> // Window defines
|
||
#include "GL/glew.h" // Dołączony jako pliki glew.c i glew.h
|
||
//#include <gl/gl.h> // OpenGL
|
||
#include <gl/glu.h> // biblioteka GLU; program kompiluje się bez niej, ale w celu uniknięcia w przyszłości niespodzianek to została dołączona
|
||
#include <math.h> // Define for sqrt
|
||
//#include <stdio.h>
|
||
#include <iostream>
|
||
#include "RESOURCE.H" // About box resource identifiers.
|
||
#include "loadOBJ.h"
|
||
#include "lazik.hpp"
|
||
#include "plane.hpp"
|
||
//#include <vector>
|
||
#include "GL/glm/glm.hpp"
|
||
#include "GL/glfw3.h"
|
||
#include <ctime>
|
||
#include "timeh.hpp"
|
||
#include "texture.hpp"
|
||
#include "shader.hpp"
|
||
#include "FPSCounter.cpp"
|
||
#include <thread>
|
||
#include "teksturowane.hpp"
|
||
#include "fabula.hpp"
|
||
#include "GL/wglew.h"
|
||
#include "Logger.hpp"
|
||
|
||
|
||
using namespace glm;
|
||
|
||
#define glRGB(x, y, z) glColor3ub((GLubyte)x, (GLubyte)y, (GLubyte)z)
|
||
#define BITMAP_ID 0x4D42 // identyfikator formatu BMP
|
||
#define GL_PI 3.1415
|
||
//#define getTime lastTime = std::time(nullptr);
|
||
//#define timestampedCout(msg) {getTime; std::cout << "( " << lastTime << ") " << msg << "\n";}
|
||
|
||
//using namespace std;
|
||
|
||
|
||
|
||
HPALETTE hPalette = NULL;
|
||
|
||
// Application name and instance storage
|
||
static LPCTSTR lpszAppName = "grafikaKBT";
|
||
static HINSTANCE hInstance;
|
||
GLFWwindow* window;
|
||
///////////////////////
|
||
void DisableQuickEdit();
|
||
|
||
void MakeShadowMatrix(GLfloat shadowMat[16], GLfloat groundplane[4], GLfloat lightpos[4]);
|
||
// Rotation amounts
|
||
static GLfloat xRot = 0.0f;
|
||
static GLfloat yRot = 0.0f;
|
||
static GLfloat zRot = 0.0f;
|
||
|
||
|
||
static GLsizei lastHeight;
|
||
static GLsizei lastWidth;
|
||
|
||
// Opis tekstury
|
||
BITMAPINFOHEADER bitmapInfoHeader; // nagłówek obrazu
|
||
unsigned char* bitmapData; // dane tekstury
|
||
unsigned int texture[4]; // obiekt tekstury
|
||
|
||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||
|
||
BOOL APIENTRY AboutDlgProc(HWND hDlg, UINT message, UINT wParam, LONG lParam);
|
||
|
||
void SetDCPixelFormat(HDC hDC);
|
||
|
||
int polygonmode = 0;
|
||
std::time_t lastTime = std::time(nullptr);
|
||
int monitormode = 1;
|
||
int monitormodecounter = 0;
|
||
std::time_t monitormodehelper;
|
||
short biezacy_wzor = 0;
|
||
bool panoramic_view = 0;
|
||
|
||
//Zmienne do ruchu ##############################################^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
FPSCounter fpsCounter;
|
||
float deltaTime = 0.0f;
|
||
|
||
|
||
static const int targetFPS = 144; // Celowany FPS
|
||
//Fps counter
|
||
static void LimitFPS(int targetFPS) {
|
||
static auto lastTime = std::chrono::high_resolution_clock::now();
|
||
|
||
// Obliczamy czas na jedną klatkę
|
||
double targetFrameDuration = 1.0 / targetFPS;
|
||
|
||
auto currentTime = std::chrono::high_resolution_clock::now();
|
||
std::chrono::duration<double> elapsed = currentTime - lastTime;
|
||
|
||
// --- CZYSTA PĘTLA (Busy Wait) ---
|
||
// Usunęliśmy sleep_for, bo w Windows jest zbyt nieprecyzyjny dla FPS > 64.
|
||
// Teraz procesor będzie pracował na 100% jednego wątku, ale FPS będzie idealny.
|
||
while (elapsed.count() < targetFrameDuration) {
|
||
// Tylko aktualizujemy czas, nic więcej.
|
||
// Jeśli chcesz trochę odciążyć CPU, można użyć instrukcji procesora 'pause',
|
||
// ale w standardowym C++ po prostu pusta pętla z pomiarem czasu jest najpewniejsza.
|
||
|
||
currentTime = std::chrono::high_resolution_clock::now();
|
||
elapsed = currentTime - lastTime;
|
||
}
|
||
|
||
lastTime = std::chrono::high_resolution_clock::now();
|
||
}
|
||
|
||
bool Kolizja = false;
|
||
bool keyWPressed = false;
|
||
bool keySPressed = false;
|
||
bool keyAPressed = false;
|
||
bool keyDPressed = false;
|
||
|
||
float Foward = 45.0f; // Pozycja łazika w przód/tył
|
||
float Sides = -45.0f; // Pozycja łazika w lewo/prawo
|
||
float Rotation = 270.0f; // Rotacja łazika (w stopniach)
|
||
|
||
|
||
bool fpv_view = false; // Flaga widoku z pierwszej osoby
|
||
|
||
const float MinDistance = 20.0f;
|
||
const float MaxDistance = 1000.0f;
|
||
float CameraHeight = 150.0f; // Wysokość kamery
|
||
float MoveSpeed = 0.5f; // Prędkość poruszania się
|
||
|
||
|
||
float velocity = 0.0f; // Aktualna prędkość łazika
|
||
float rotationVelocity = 0.0f; // Prędkość obrotu łazika
|
||
|
||
|
||
const float friction = 0.05f; // Współczynnik tarcia (μ)
|
||
const float maxSpeed = 2.0f; // Maksymalna prędkość łazika
|
||
const float acceleration = 0.2f;
|
||
|
||
|
||
float rotationAcceleration = 0.075f; // Przyspieszenie obrotu
|
||
float rotationFriction = 0.1f; // Współczynnik tarcia obrotu
|
||
float maxRotationSpeed = 0.5f; // Maksymalna prędkość obrotu
|
||
|
||
// Struktura do reprezentacji płotu
|
||
struct Plot {
|
||
GLfloat xc; // Środek płotu w osi X
|
||
GLfloat yc; // Środek (nieużywany w 2D)
|
||
GLfloat zc; // Środek płotu w osi Z
|
||
GLfloat length; // Długość (dłuższy wymiar)
|
||
GLfloat grubosc; // Szerokość/Grubość (krótszy wymiar)
|
||
bool mod_x; // 0 - płot wzdłuż osi Z (pionowy), 1 - płot wzdłuż osi X (poziomy)
|
||
};
|
||
|
||
static bool CheckFenceCollision(float rXMin, float rXMax, float rZMin, float rZMax, const Plot& plot) {
|
||
float fXMin, fXMax, fZMin, fZMax;
|
||
|
||
if (plot.mod_x == 0) { // Płot pionowy (rozciąga się w osi Z)
|
||
fXMin = plot.xc - plot.grubosc / 2.0f;
|
||
fXMax = plot.xc + plot.grubosc / 2.0f;
|
||
fZMin = plot.zc - plot.length / 2.0f;
|
||
fZMax = plot.zc + plot.length / 2.0f;
|
||
} else { // Płot poziomy (rozciąga się w osi X)
|
||
fXMin = plot.xc - plot.length / 2.0f;
|
||
fXMax = plot.xc + plot.length / 2.0f;
|
||
fZMin = plot.zc - plot.grubosc / 2.0f;
|
||
fZMax = plot.zc + plot.grubosc / 2.0f;
|
||
}
|
||
|
||
// Standardowy test nakładania się prostokątów (AABB vs AABB)
|
||
return (rXMax >= fXMin && rXMin <= fXMax &&
|
||
rZMax >= fZMin && rZMin <= fZMax);
|
||
}
|
||
|
||
static bool CheckAllFencesCollision(float rXMin, float rXMax, float rZMin, float rZMax, const std::vector<Plot>& fences) {
|
||
for (const auto& fence : fences) {
|
||
if (CheckFenceCollision(rXMin, rXMax, rZMin, rZMax, fence)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
static void UpdateRover(const std::vector<Plot>& fences) {
|
||
// --- SKALOWANIE CZASU ---
|
||
// Twoje stałe (acceleration, maxSpeed) były ustawione pod 144 FPS.
|
||
// Mnożnik timeScale sprawia, że fizyka działa tak samo, ale jest niezależna od klatek.
|
||
// Jeśli deltaTime = 1/144, to timeScale = 1.0 (czyli bez zmian).
|
||
// Jeśli FPS spadnie, timeScale wzrośnie, kompensując spowolnienie.
|
||
float timeScale = deltaTime * 144.0f;
|
||
|
||
// Zabezpieczenie na wypadek ekstremalnie niskiego FPS (np. przy ładowaniu),
|
||
// żeby łazik nie przeleciał przez ścianę w jednej klatce.
|
||
if (timeScale > 5.0f) timeScale = 5.0f;
|
||
|
||
// --- 1. OBSŁUGA PRZYSPIESZENIA (W / S) ---
|
||
if (keyWPressed) {
|
||
velocity += acceleration * timeScale;
|
||
if (velocity > maxSpeed) velocity = maxSpeed;
|
||
}
|
||
else if (keySPressed) {
|
||
velocity -= acceleration * timeScale;
|
||
if (velocity < -maxSpeed) velocity = -maxSpeed;
|
||
}
|
||
else {
|
||
// Hamowanie (tarcie)
|
||
float frictionStep = friction * timeScale;
|
||
|
||
if (velocity > 0) {
|
||
velocity -= frictionStep;
|
||
if (velocity < 0) velocity = 0;
|
||
}
|
||
else if (velocity < 0) {
|
||
velocity += frictionStep;
|
||
if (velocity > 0) velocity = 0;
|
||
}
|
||
}
|
||
|
||
// --- 2. OBSŁUGA OBROTU (A / D) ---
|
||
if (keyAPressed) {
|
||
rotationVelocity += rotationAcceleration * timeScale;
|
||
if (rotationVelocity > maxRotationSpeed) rotationVelocity = maxRotationSpeed;
|
||
}
|
||
else if (keyDPressed) {
|
||
rotationVelocity -= rotationAcceleration * timeScale;
|
||
if (rotationVelocity < -maxRotationSpeed) rotationVelocity = -maxRotationSpeed;
|
||
}
|
||
else {
|
||
// Driftowanie (wytracanie rotacji)
|
||
float driftFactor = 0.1f;
|
||
float rotationFrictionStep = rotationFriction * driftFactor * timeScale;
|
||
|
||
if (rotationVelocity > 0) {
|
||
rotationVelocity -= rotationFrictionStep;
|
||
if (rotationVelocity < 0) rotationVelocity = 0;
|
||
}
|
||
else if (rotationVelocity < 0) {
|
||
rotationVelocity += rotationFrictionStep;
|
||
if (rotationVelocity > 0) rotationVelocity = 0;
|
||
}
|
||
}
|
||
|
||
// --- 3. LOGIKA ODWRÓCENIA SKRĘTU PRZY COFANIU ---
|
||
// Tutaj też stosujemy timeScale do obliczenia faktycznego kroku obrotu w tej klatce
|
||
float actualRotationStep = rotationVelocity * timeScale;
|
||
|
||
if (velocity < 0.0f) {
|
||
actualRotationStep = -actualRotationStep;
|
||
}
|
||
|
||
// --- 4. WYLICZENIE NOWEJ POZYCJI ---
|
||
// Obliczamy przesunięcie w tej klatce (velocity to jednostki na klatkę przy 144fps, więc mnożymy przez timeScale)
|
||
float currentMoveStep = velocity * timeScale;
|
||
|
||
float radRotation = Rotation * GL_PI / 180.0f;
|
||
float newSides = Sides - currentMoveStep * cos(radRotation);
|
||
float newFoward = Foward - currentMoveStep * sin(radRotation);
|
||
|
||
// Wymiary łazika
|
||
const float roverHalfWidthX = 19.0f;
|
||
const float roverHalfLengthZ = 12.0f;
|
||
|
||
// Obszar zajmowany przez łazik (AABB dla ruchu prostoliniowego)
|
||
float roverXMin = newSides - roverHalfWidthX;
|
||
float roverXMax = newSides + roverHalfWidthX;
|
||
float roverZMin = newFoward - roverHalfLengthZ;
|
||
float roverZMax = newFoward + roverHalfLengthZ;
|
||
|
||
// --- 5. KOLIZJE I AKTUALIZACJA ---
|
||
if (!Kolizja) {
|
||
// Kolizja przy ruchu przód/tył
|
||
if (CheckAllFencesCollision(roverZMin, roverZMax, roverXMin, roverXMax, fences)) {
|
||
velocity = 0.0f;
|
||
// Opcjonalnie: minimalne odbicie, żeby nie "kleił" się do ściany
|
||
// velocity = -velocity * 0.1f;
|
||
}
|
||
else {
|
||
Sides = newSides;
|
||
Foward = newFoward;
|
||
}
|
||
|
||
// Kolizja przy obrocie
|
||
if (actualRotationStep != 0.0f) {
|
||
float newRotation = Rotation + actualRotationStep;
|
||
float radNewRotation = newRotation * GL_PI / 180.0f;
|
||
|
||
// Punkty narożne do sprawdzenia po obrocie (OBB - uproszczone sprawdzenie narożników)
|
||
// Używamy zaktualizowanych Sides/Foward (jeśli ruch do przodu się udał)
|
||
std::vector<std::pair<float, float>> corners = {
|
||
{Sides - roverHalfWidthX, Foward - roverHalfLengthZ},
|
||
{Sides + roverHalfWidthX, Foward - roverHalfLengthZ},
|
||
{Sides - roverHalfWidthX, Foward + roverHalfLengthZ},
|
||
{Sides + roverHalfWidthX, Foward + roverHalfLengthZ}
|
||
};
|
||
|
||
bool collisionDetected = false;
|
||
for (auto& corner : corners) {
|
||
float x = corner.first;
|
||
float z = corner.second;
|
||
|
||
// Rotacja punktów wokół środka łazika
|
||
float rotatedX = Sides + (x - Sides) * cos(radNewRotation) - (z - Foward) * sin(radNewRotation);
|
||
float rotatedZ = Foward + (x - Sides) * sin(radNewRotation) + (z - Foward) * cos(radNewRotation);
|
||
|
||
// Sprawdzamy czy punkt (o bardzo małym promieniu) wchodzi w płot
|
||
// Dla uproszczenia traktujemy punkt jako malutki kwadrat +/- 1.0f
|
||
if (CheckAllFencesCollision(rotatedZ - 1.0f, rotatedZ + 1.0f, rotatedX - 1.0f, rotatedX + 1.0f, fences)) {
|
||
collisionDetected = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (collisionDetected) {
|
||
rotationVelocity = 0.0f; // Blokujemy obrót
|
||
}
|
||
else {
|
||
Rotation = newRotation;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
// Kolizje wyłączone - aktualizuj bez pytań
|
||
Sides = newSides;
|
||
Foward = newFoward;
|
||
Rotation += actualRotationStep;
|
||
}
|
||
|
||
// Normalizacja kąta do zakresu 0-360
|
||
if (Rotation >= 360.0f) Rotation -= 360.0f;
|
||
if (Rotation < 0.0f) Rotation += 360.0f;
|
||
}
|
||
|
||
std::vector<Plot> fences = {
|
||
{ 450.0f, 3.0f, -90.0f, 900.0f, 4.0f, 1}, // 1 - poziomo
|
||
{ 0.0f, 3.0f, 405.0f, 990.0f, 4.0f, 0}, // 0 - pionowo
|
||
{ 450.0f, 3.0f, 10*90.0f, 900.0f, 4.0f, 1}, // 1 - poziomo
|
||
{10*90.0f, 3.0f, 405.0f, 990.0f, 4.0f, 0} // 0 - pionowo
|
||
};
|
||
|
||
// Change viewing volume and viewport. Called when window is resized
|
||
void static ChangeSize(GLsizei w, GLsizei h) {
|
||
// Zabezpieczenie przed dzieleniem przez zero
|
||
if (h == 0) h = 1;
|
||
|
||
lastWidth = w;
|
||
lastHeight = h;
|
||
|
||
// Obliczenie proporcji okna (Aspect Ratio)
|
||
GLfloat fAspect = (GLfloat)w / (GLfloat)h;
|
||
|
||
// Ustawienie obszaru renderowania
|
||
glViewport(0, 0, w, h);
|
||
|
||
// Reset macierzy projekcji
|
||
glMatrixMode(GL_PROJECTION);
|
||
glLoadIdentity();
|
||
|
||
// USTAWIENIE PERSPEKTYWY
|
||
// Parametry: (Kąt widzenia w stopniach, Proporcje okna, Bliska płaszczyzna, Daleka płaszczyzna)
|
||
// UWAGA: Bliska płaszczyzna (near) w perspektywie MUSI być większa od 0 (np. 1.0f)
|
||
gluPerspective(45.0f, fAspect, 1.0f, 2000.0f);
|
||
|
||
// Powrót do macierzy widoku modelu
|
||
glMatrixMode(GL_MODELVIEW);
|
||
glLoadIdentity();
|
||
}
|
||
|
||
// LoadBitmapFile
|
||
// opis: ładuje mapę bitową z pliku i zwraca jej adres.
|
||
// Wypełnia strukturę nagłówka.
|
||
// Nie obsługuje map 8-bitowych.
|
||
static unsigned char* LoadBitmapFile(char* filename, BITMAPINFOHEADER* bitmapInfoHeader) {
|
||
FILE* filePtr; // wskaźnik pozycji pliku
|
||
BITMAPFILEHEADER bitmapFileHeader; // nagłówek pliku
|
||
unsigned char* bitmapImage; // dane obrazu
|
||
int imageIdx = 0; // licznik pikseli
|
||
unsigned char tempRGB; // zmienna zamiany składowych
|
||
|
||
// otwiera plik w trybie "read binary"
|
||
filePtr = fopen(filename, "rb");
|
||
if (filePtr == NULL) return NULL;
|
||
|
||
// wczytuje nagłówek pliku
|
||
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
|
||
|
||
// sprawdza, czy jest to plik formatu BMP
|
||
if (bitmapFileHeader.bfType != BITMAP_ID) {
|
||
fclose(filePtr);
|
||
return NULL;
|
||
}
|
||
|
||
// wczytuje nagłówek obrazu
|
||
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
|
||
|
||
// ustawia wskaźnik pozycji pliku na początku danych obrazu
|
||
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
|
||
|
||
// przydziela pamięć buforowi obrazu
|
||
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
|
||
|
||
// sprawdza, czy udało się przydzielić pamięć
|
||
if (!bitmapImage) {
|
||
free(bitmapImage);
|
||
fclose(filePtr);
|
||
return NULL;
|
||
}
|
||
|
||
// wczytuje dane obrazu
|
||
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);
|
||
|
||
// sprawdza, czy dane zostały wczytane
|
||
if (bitmapImage == NULL) {
|
||
fclose(filePtr);
|
||
return NULL;
|
||
}
|
||
|
||
// zamienia miejscami składowe R i B
|
||
for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3) {
|
||
tempRGB = bitmapImage[imageIdx];
|
||
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
|
||
bitmapImage[imageIdx + 2] = tempRGB;
|
||
}
|
||
|
||
// zamyka plik i zwraca wskaźnik bufora zawierającego wczytany obraz
|
||
fclose(filePtr);
|
||
return bitmapImage;
|
||
}
|
||
|
||
void SetDCPixelFormat(HDC hDC) {
|
||
int nPixelFormat;
|
||
|
||
static PIXELFORMATDESCRIPTOR pfd = {
|
||
sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
|
||
1, // Version of this structure
|
||
PFD_DRAW_TO_WINDOW | // Draw to Window (not to bitmap)
|
||
PFD_SUPPORT_OPENGL | // Support OpenGL calls in window
|
||
PFD_DOUBLEBUFFER, // Double buffered
|
||
PFD_TYPE_RGBA, // RGBA Color mode
|
||
24, // Want 24bit color
|
||
0, 0, 0, 0, 0, 0, // Not used to select mode
|
||
0, 0, // Not used to select mode
|
||
0, 0, 0, 0, 0, // Not used to select mode
|
||
32, // Size of depth buffer
|
||
0, // Not used to select mode
|
||
0, // Not used to select mode
|
||
PFD_MAIN_PLANE, // Draw in main plane
|
||
0, // Not used to select mode
|
||
0, 0, 0 }; // Not used to select mode
|
||
|
||
// Choose a pixel format that best matches that described in pfd
|
||
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
|
||
|
||
// Set the pixel format for the device context
|
||
SetPixelFormat(hDC, nPixelFormat, &pfd);
|
||
}
|
||
|
||
//GLuint programID, VertexArrayID, MatrixID;
|
||
lazik user(10.0f, 0.0f, 0.0f, "res/models/lazik4.obj"); // obiekty eksportujemy z Forward Axis Z, Up Axis Y.
|
||
plane mapa( 0.0f, 0.0f, 0.0f, "res/models/mapka3_nofence_noplatform.obj");
|
||
|
||
static void SetupRC() {
|
||
// 1. Podstawowe ustawienia OpenGL
|
||
glEnable(GL_DEPTH_TEST); // Usuwanie niewidocznych powierzchni
|
||
glFrontFace(GL_CCW); // Przeciwnie do ruchu wskazówek zegara to przód
|
||
glDepthFunc(GL_LESS);
|
||
|
||
glEnable(GL_MULTISAMPLE); // Antyaliasing
|
||
glEnable(GL_LINE_SMOOTH);
|
||
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
|
||
|
||
// 2. KLUCZOWE: Normalizacja wektorów
|
||
// Bez tego, jeśli skalujesz modele, oświetlenie wariuje.
|
||
glEnable(GL_NORMALIZE);
|
||
|
||
// 3. Konfiguracja kolorów światła
|
||
// Ambient - światło otoczenia (cienie nie będą czarne, ale lekko szare)
|
||
GLfloat ambientLight[] = { 0.4f, 0.4f, 0.4f, 1.0f };
|
||
|
||
// Diffuse - główny kolor światła słonecznego (lekko ciepły biały)
|
||
GLfloat diffuseLight[] = { 0.9f, 0.9f, 0.8f, 1.0f };
|
||
|
||
// Specular - kolor odbłysku (zmniejszamy intensywność, żeby nie raziło)
|
||
GLfloat specular[] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||
|
||
// 4. Pozycje świateł
|
||
// LIGHT0 - SŁOŃCE (Kluczowa zmiana)
|
||
// Czwarty parametr 0.0f oznacza światło KIERUNKOWE (z nieskończoności), a nie punktowe.
|
||
// Ustawiamy je wysoko w górze (Y=100) i pod kątem.
|
||
GLfloat sunPos[] = { 100.0f, 150.0f, 100.0f, 0.0f };
|
||
|
||
// LIGHT1 - Doświetlenie cieni (opcjonalne, "fill light" z drugiej strony)
|
||
GLfloat fillPos[] = { -100.0f, 50.0f, -100.0f, 0.0f };
|
||
GLfloat fillDiffuse[] = { 0.3f, 0.3f, 0.4f, 1.0f }; // Niebieskawe, słabsze światło
|
||
|
||
// 5. Włączenie oświetlenia
|
||
glEnable(GL_LIGHTING);
|
||
|
||
// Konfiguracja Słońca (LIGHT0)
|
||
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
|
||
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
|
||
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
|
||
glLightfv(GL_LIGHT0, GL_POSITION, sunPos);
|
||
glEnable(GL_LIGHT0);
|
||
|
||
// Konfiguracja doświetlenia (LIGHT1) - łagodzi ostre cienie
|
||
glLightfv(GL_LIGHT1, GL_AMBIENT, ambientLight); // Wspólny ambient
|
||
glLightfv(GL_LIGHT1, GL_DIFFUSE, fillDiffuse);
|
||
glLightfv(GL_LIGHT1, GL_POSITION, fillPos);
|
||
glEnable(GL_LIGHT1);
|
||
// LIGHT2 i LIGHT3 możesz wyłączyć dla wydajności, chyba że robisz reflektory łazika
|
||
|
||
// 6. Materiały
|
||
glEnable(GL_COLOR_MATERIAL);
|
||
// Kolor obiektu wpływa na światło rozproszone (diffuse) i otoczenia (ambient)
|
||
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
|
||
|
||
// Zmniejszamy połyskliwość, żeby trawa nie wyglądała jak szkło
|
||
GLfloat specref2[] = { 0.1f, 0.1f, 0.1f, 1.0f }; // Bardzo słaby odbłysk materiału
|
||
glMaterialfv(GL_FRONT, GL_SPECULAR, specref2);
|
||
glMateriali(GL_FRONT, GL_SHININESS, 10); // Zmniejszono ze 128 na 10 (bardziej matowe)
|
||
|
||
// Tło (Błękitne niebo zamiast białego)
|
||
glClearColor(0.53f, 0.81f, 0.92f, 1.0f);
|
||
|
||
// --- Reszta Twojej inicjalizacji (GLEW, GLFW, modele) bez zmian ---
|
||
timestampedCout("Inicjalizowanie GLEW...");
|
||
glewExperimental = true;
|
||
if (glewInit() != GLEW_OK) {
|
||
timestampedCout("Failed to initialize GLEW");
|
||
return;
|
||
}
|
||
// ... reszta kodu SetupRC ...
|
||
timestampedCout("Zainicjalizowano GLEW.");
|
||
if (wglewIsSupported("WGL_EXT_swap_control")) {
|
||
wglSwapIntervalEXT(0);
|
||
timestampedCout("V-Sync wylaczony (unlocked FPS).");
|
||
}
|
||
else {
|
||
timestampedCout("Brak obslugi WGL_EXT_swap_control - nie mozna programowo wylaczyc V-Sync.");
|
||
}
|
||
|
||
timestampedCout("Inicjalizowanie GLFW3...");
|
||
if (!glfwInit()) {
|
||
timestampedCout("Failed to initialize GLFW");
|
||
}
|
||
timestampedCout("Zainicjalizowano GLFW3.");
|
||
|
||
timestampedCout("Ladowanie modelu lazika...");
|
||
user.loadModel();
|
||
timestampedCout("Ladowanie modelu mapki...");
|
||
mapa.loadModel();
|
||
|
||
glfwSwapInterval(0);
|
||
}
|
||
|
||
|
||
void static RenderScene(void) {
|
||
|
||
// PS: to nie zadziała, bo okno nie jest tworzone przez glfw
|
||
// Ustawienie liczby próbek dla antyaliasingu
|
||
glfwWindowHint(GLFW_SAMPLES, 16); // 4x MSAA (Wielokrotne próbkowanie)
|
||
|
||
// Włączenie antyaliasingu (MSAA)
|
||
glEnable(GL_MULTISAMPLE);
|
||
|
||
// Przywrócenie macierzy modelu i ustawienie obrotów
|
||
glPushMatrix();
|
||
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
|
||
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
|
||
glRotatef(zRot, 0.0f, 0.0f, 1.0f);
|
||
|
||
// Ustawienie trybu rysowania wielokątów
|
||
switch (polygonmode) {
|
||
case 1:
|
||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Rysowanie linii
|
||
break;
|
||
default:
|
||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // Wypełnianie poligonów
|
||
}
|
||
|
||
// Czyszczenie ekranu przed rysowaniem
|
||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||
|
||
// Widok panoramiczny (SHIFT/F5)
|
||
// Pomocnicza konwersja na radiany
|
||
float rad = Rotation * GL_PI / 180.0f;
|
||
|
||
if (panoramic_view) {
|
||
// --- WIDOK Z GÓRY ---
|
||
maxRotationSpeed = 1.0f;
|
||
rotationFriction = 0.5f;
|
||
float mapZoom = 400.0f;
|
||
gluLookAt(Foward, mapZoom, Sides, Foward, 0.0f, Sides, 1.0f, 0.0f, 0.0f);
|
||
}
|
||
else if (fpv_view) {
|
||
// --- WIDOK FIRST PERSON (FPV) ---
|
||
maxRotationSpeed = 0.5f;
|
||
rotationFriction = 0.1f;
|
||
|
||
float rad = Rotation * GL_PI / 180.0f;
|
||
|
||
// Pozycja oczu: środek łazika + lekko w górę
|
||
float eyeX = Foward;
|
||
float eyeY = 15.0f; // Wysokość "oczu" nad ziemią
|
||
float eyeZ = Sides;
|
||
|
||
// Kierunek patrzenia: zgodnie z rotacją łazika
|
||
// Używamy ujemnego sin/cos, bo w Twoim kodzie Rotation steruje modelem w ten sposób
|
||
float lookAtX = Foward - 10.0f * sin(rad);
|
||
float lookAtZ = Sides - 10.0f * cos(rad);
|
||
|
||
gluLookAt(
|
||
eyeX, eyeY, eyeZ, // Oko jest wewnątrz/nad łazikiem
|
||
lookAtX, eyeY, lookAtZ, // Patrzymy przed siebie (na tej samej wysokości)
|
||
0.0f, 1.0f, 0.0f // Góra to oś Y
|
||
);
|
||
}
|
||
else {
|
||
// --- WIDOK TRZECIOOSOBOWY (TPP) ---
|
||
maxRotationSpeed = 0.5f;
|
||
rotationFriction = 0.1f;
|
||
float rad = Rotation * GL_PI / 180.0f;
|
||
float camX = Foward + CameraHeight * sin(rad);
|
||
float camZ = Sides + CameraHeight * cos(rad);
|
||
float dynamicHeight = CameraHeight * 0.4f;
|
||
|
||
gluLookAt(camX, dynamicHeight, camZ, Foward, 10.0f, Sides, 0.0f, 1.0f, 0.0f);
|
||
|
||
}
|
||
|
||
|
||
// Rysowanie mapy
|
||
glPushMatrix();
|
||
// glColor3f(0.0, 1.0, 0.0); // Zielony kolor
|
||
// mapa.draw(); // nie rysuj mapy/terenu .obj
|
||
|
||
// Platforma niebędąca częścią siatki:
|
||
glColor3d(0.031, 0.51, 0.094); // ciemnozielony
|
||
platforma(450.0f, 0.0f, -45.0f, 450.0f, 45.0f);
|
||
glPopMatrix();
|
||
|
||
// Rysowanie łazika
|
||
glPushMatrix();
|
||
glTranslatef(Foward, 0.0f, Sides); // Translacja łazika
|
||
glRotatef(Rotation, 0.0f, 1.0f, 0.0f); // Obrót łazika
|
||
glColor3f(1.0, 0.0, 0.0); // Czerwony kolor dla łazika
|
||
user.draw(); // Rysuj łazik z pomocą lazik.cpp
|
||
UpdateRover(fences);
|
||
fpsCounter.update();
|
||
glPopMatrix();
|
||
|
||
// std::cout << "X: " << Foward << " Z: " << Sides << " Rotation: " << Rotation << "\n";
|
||
|
||
// Rysowanie innych obiektów
|
||
// 1 pole siatki = 90x90m
|
||
plot( 450.0f, 3.0f, -90.0f, 900.0f, 4.0f, 1); // 1 - poziomo
|
||
plot( 0.0f, 3.0f, 405.0f, 990.0f, 4.0f, 0); // 0 - pionowo
|
||
plot( 450.0f, 3.0f, 10*90.0f, 900.0f, 4.0f, 1); // 1 - poziomo
|
||
plot(10*90.0f, 3.0f, 405.0f, 990.0f, 4.0f, 0); // 0 - pionowo
|
||
stodola(45.0f, 0.0f, -45.0f, 70.0f);
|
||
|
||
// Mechanika gry
|
||
short grid_x, grid_z;
|
||
ustalPozycjeGracza(Foward, Sides, grid_x, grid_z);
|
||
// std::cout << "grid_X: " << grid_x << " grid_Z: " << grid_z << " status: " << siatka[10*grid_x + (9 - grid_z)] << "\n";
|
||
ustawSiatkeNaWzorNieNadpisujacPostepu();
|
||
tworzKratkiZSiatki();
|
||
aktualizujBiezacaKratke(grid_x, grid_z);
|
||
|
||
// Zamiana buforów (double buffering)
|
||
// glfwSwapBuffers(window); // Przełączenie buforów
|
||
// glfwPollEvents(); // Obsługa zdarzeń
|
||
|
||
glPopMatrix(); // Przywrócenie poprzedniej macierzy
|
||
glMatrixMode(GL_MODELVIEW); // Ustawienie trybu modelu-widoku
|
||
|
||
// Wymuszenie wykonania wszystkich rysunków
|
||
glFlush();
|
||
|
||
}
|
||
|
||
|
||
// If necessary, creates a 3-3-2 palette for the device context listed.
|
||
HPALETTE static GetOpenGLPalette(HDC hDC) {
|
||
HPALETTE hRetPal = NULL; // Handle to palette to be created
|
||
PIXELFORMATDESCRIPTOR pfd; // Pixel Format Descriptor
|
||
LOGPALETTE* pPal; // Pointer to memory for logical palette
|
||
int nPixelFormat; // Pixel format index
|
||
int nColors; // Number of entries in palette
|
||
int i; // Counting variable
|
||
BYTE RedRange, GreenRange, BlueRange;
|
||
// Range for each color entry (7,7,and 3)
|
||
|
||
|
||
// Get the pixel format index and retrieve the pixel format description
|
||
nPixelFormat = GetPixelFormat(hDC);
|
||
DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
||
|
||
// Does this pixel format require a palette? If not, do not create a
|
||
// palette and just return NULL
|
||
if (!(pfd.dwFlags & PFD_NEED_PALETTE)) return NULL;
|
||
|
||
// Number of entries in palette. 8 bits yeilds 256 entries
|
||
nColors = 1 << pfd.cColorBits;
|
||
|
||
// Allocate space for a logical palette structure plus all the palette entries
|
||
pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + nColors * sizeof(PALETTEENTRY));
|
||
|
||
// Fill in palette header
|
||
pPal->palVersion = 0x300; // Windows 3.0
|
||
pPal->palNumEntries = nColors; // table size
|
||
|
||
// Build mask of all 1's. This creates a number represented by having
|
||
// the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
|
||
// pfd.cBlueBits.
|
||
RedRange = (1 << pfd.cRedBits) - 1;
|
||
GreenRange = (1 << pfd.cGreenBits) - 1;
|
||
BlueRange = (1 << pfd.cBlueBits) - 1;
|
||
|
||
// Loop through all the palette entries
|
||
for (i = 0; i < nColors; i++) {
|
||
|
||
// Fill in the 8-bit equivalents for each component
|
||
pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
|
||
pPal->palPalEntry[i].peRed = (unsigned char)(
|
||
(double)pPal->palPalEntry[i].peRed * 255.0 / RedRange);
|
||
|
||
pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
|
||
pPal->palPalEntry[i].peGreen = (unsigned char)(
|
||
(double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);
|
||
|
||
pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
|
||
pPal->palPalEntry[i].peBlue = (unsigned char)(
|
||
(double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);
|
||
|
||
// pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
|
||
pPal->palPalEntry[i].peFlags = 0;
|
||
}
|
||
|
||
|
||
// Create the palette
|
||
hRetPal = CreatePalette(pPal);
|
||
|
||
// Go ahead and select and realize the palette for this device context
|
||
SelectPalette(hDC, hRetPal, FALSE);
|
||
RealizePalette(hDC);
|
||
|
||
// Free the memory used for the logical palette structure
|
||
free(pPal);
|
||
|
||
// Return the handle to the new palette
|
||
return hRetPal;
|
||
}
|
||
|
||
void static CreateConsole() {
|
||
|
||
// Tworzenie nowej konsoli
|
||
if (AllocConsole()) {
|
||
// Przekierowanie standardowych strumieni do konsoli
|
||
FILE* conin;
|
||
FILE* conout;
|
||
FILE* conerr;
|
||
freopen_s(&conin, "conin$", "r", stdin);
|
||
freopen_s(&conout, "conout$", "w", stdout);
|
||
freopen_s(&conerr, "conout$", "w", stderr);
|
||
} else {
|
||
MessageBox(NULL, "Nie udalo sie utworzyc konsoli.", "Blad", MB_OK | MB_ICONERROR);
|
||
}
|
||
|
||
}
|
||
|
||
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||
|
||
CreateConsole();
|
||
DisableQuickEdit();
|
||
AsyncLogger::getInstance().start();
|
||
MSG msg;
|
||
WNDCLASS wc{};
|
||
HWND hWnd;
|
||
|
||
hInstance = hInst;
|
||
|
||
// Rejestracja klasy okna
|
||
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // DODANO CS_OWNDC - ważne dla OpenGL
|
||
wc.lpfnWndProc = (WNDPROC)WndProc;
|
||
wc.cbClsExtra = 0;
|
||
wc.cbWndExtra = 0;
|
||
wc.hInstance = hInstance;
|
||
wc.hIcon = NULL;
|
||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||
wc.hbrBackground = NULL;
|
||
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
|
||
wc.lpszClassName = lpszAppName;
|
||
|
||
if (RegisterClass(&wc) == 0) return FALSE;
|
||
|
||
hWnd = CreateWindow(
|
||
lpszAppName, lpszAppName,
|
||
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
||
50, 50, 800, 800,
|
||
NULL, NULL, hInstance, NULL);
|
||
|
||
if (hWnd == NULL) return FALSE;
|
||
|
||
// --- POPRAWKA 1: Pobierz HDC raz ---
|
||
HDC hDC = GetDC(hWnd);
|
||
|
||
const WORD ID_TIMER = 1;
|
||
SetTimer(hWnd, ID_TIMER, 100, NULL);
|
||
|
||
ShowWindow(hWnd, SW_SHOW);
|
||
UpdateWindow(hWnd);
|
||
|
||
|
||
|
||
ZeroMemory(&msg, sizeof(msg));
|
||
auto lastFrameTime = std::chrono::high_resolution_clock::now();
|
||
while (msg.message != WM_QUIT) {
|
||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||
TranslateMessage(&msg);
|
||
DispatchMessage(&msg);
|
||
}
|
||
else {
|
||
auto currentFrameTime = std::chrono::high_resolution_clock::now();
|
||
std::chrono::duration<float> timeSpan = currentFrameTime - lastFrameTime;
|
||
deltaTime = timeSpan.count(); // Czas w sekundach (np. 0.0069 przy 144 FPS)
|
||
lastFrameTime = currentFrameTime;
|
||
RenderScene();
|
||
|
||
// --- POPRAWKA 2: Używaj zapisanego hDC, a nie pobieraj nowego ---
|
||
SwapBuffers(hDC);
|
||
LOG("FPS: " << fpsCounter.getFPS() << " | Czas: " << fpsCounter.getFrameTime() << "ms");
|
||
LimitFPS(targetFPS);
|
||
}
|
||
}
|
||
|
||
// --- POPRAWKA 3: Zwolnij HDC przy zamykaniu ---
|
||
ReleaseDC(hWnd, hDC);
|
||
|
||
return msg.wParam;
|
||
}
|
||
|
||
|
||
// Window procedure, handles all messages for this program
|
||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||
static HGLRC hRC; // Permenant Rendering context
|
||
static HDC hDC; // Private GDI Device context
|
||
|
||
float radRotation = Rotation * GL_PI / 180.0f;
|
||
switch (message) {
|
||
// Window creation, setup for OpenGL
|
||
case WM_CREATE:
|
||
{
|
||
// 1. NAJPIERW INICJALIZACJA KONTEKSTU WINDOWS I OPENGL
|
||
// Bez tego funkcje gl... nie będą działać!
|
||
hDC = GetDC(hWnd);
|
||
SetDCPixelFormat(hDC);
|
||
hPalette = GetOpenGLPalette(hDC);
|
||
hRC = wglCreateContext(hDC);
|
||
wglMakeCurrent(hDC, hRC);
|
||
|
||
// Inicjalizacja GLEW i modeli (Twoja funkcja)
|
||
SetupRC();
|
||
|
||
// 2. SPRAWDZENIE MOŻLIWOŚCI KARTY GRAFICZNEJ
|
||
GLfloat fLargest;
|
||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
|
||
|
||
// 3. GENEROWANIE OBIEKTÓW TEKSTUR
|
||
// Używasz indeksów 0, 1, 2, 3 – więc potrzebujesz 4 slotów
|
||
glGenTextures(4, &texture[0]);
|
||
|
||
// --- TEKSTURA 0: PŁOTKI ---
|
||
bitmapData = LoadBitmapFile((char*)"res/img/woodenTextureHighExposure.bmp", &bitmapInfoHeader);
|
||
if (bitmapData) {
|
||
glBindTexture(GL_TEXTURE_2D, texture[0]);
|
||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest); // Ostrość pod kątem
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Rozdzielczość w dali (Mipmapy)
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Rozdzielczość z bliska
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
|
||
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, bitmapInfoHeader.biWidth, bitmapInfoHeader.biHeight, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);
|
||
free(bitmapData);
|
||
}
|
||
|
||
// --- TEKSTURA 1: ZIEMIA (Najważniejsza dla efektu oddali) ---
|
||
bitmapData = LoadBitmapFile((char*)"res/img/grass02.bmp", &bitmapInfoHeader);
|
||
if (bitmapData) {
|
||
glBindTexture(GL_TEXTURE_2D, texture[1]);
|
||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
|
||
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, bitmapInfoHeader.biWidth, bitmapInfoHeader.biHeight, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);
|
||
free(bitmapData);
|
||
}
|
||
|
||
// --- TEKSTURA 2: DACH STODOŁY ---
|
||
bitmapData = LoadBitmapFile((char*)"res/img/barnroof.bmp", &bitmapInfoHeader);
|
||
if (bitmapData) {
|
||
glBindTexture(GL_TEXTURE_2D, texture[2]);
|
||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, bitmapInfoHeader.biWidth, bitmapInfoHeader.biHeight, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);
|
||
free(bitmapData);
|
||
}
|
||
|
||
// --- TEKSTURA 3: ŚCIANA ---
|
||
bitmapData = LoadBitmapFile((char*)"res/img/brickwall.bmp", &bitmapInfoHeader);
|
||
if (bitmapData) {
|
||
glBindTexture(GL_TEXTURE_2D, texture[3]);
|
||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, bitmapInfoHeader.biWidth, bitmapInfoHeader.biHeight, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);
|
||
free(bitmapData);
|
||
}
|
||
|
||
// Ustalenie sposobu mieszania tekstury z tłem
|
||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||
}
|
||
break;
|
||
|
||
// Window is being destroyed, cleanup
|
||
case WM_DESTROY:
|
||
|
||
user.unload();
|
||
//glDeleteProgram(programID);
|
||
//glDeleteVertexArrays(1, &VertexArrayID);
|
||
|
||
// Deselect the current rendering context and delete it
|
||
wglMakeCurrent(hDC, NULL);
|
||
wglDeleteContext(hRC);
|
||
|
||
// Delete the palette if it was created
|
||
if (hPalette != NULL) DeleteObject(hPalette);
|
||
|
||
// Tell the application to terminate after the window
|
||
// is gone.
|
||
PostQuitMessage(0);
|
||
AsyncLogger::getInstance().stop();
|
||
break;
|
||
|
||
// Window is resized.
|
||
case WM_SIZE:
|
||
|
||
// Call our function which modifies the clipping
|
||
// volume and viewport
|
||
ChangeSize(LOWORD(lParam), HIWORD(lParam));
|
||
break;
|
||
|
||
// The painting function. This message sent by Windows
|
||
// whenever the screen needs updating.
|
||
case WM_PAINT:
|
||
|
||
ValidateRect(hWnd, NULL);
|
||
|
||
break;
|
||
|
||
case WM_QUERYNEWPALETTE:
|
||
// If the palette was created.
|
||
if (hPalette) {
|
||
int nRet;
|
||
|
||
// Selects the palette into the current device context
|
||
SelectPalette(hDC, hPalette, FALSE);
|
||
|
||
// Map entries from the currently selected palette to
|
||
// the system palette. The return value is the number
|
||
// of palette entries modified.
|
||
nRet = RealizePalette(hDC);
|
||
|
||
// Repaint, forces remap of palette in current window
|
||
InvalidateRect(hWnd, NULL, FALSE);
|
||
|
||
return nRet;
|
||
}
|
||
break;
|
||
|
||
// This window may set the palette, even though it is not the
|
||
// currently active window.
|
||
case WM_PALETTECHANGED:
|
||
// Don't do anything if the palette does not exist, or if
|
||
// this is the window that changed the palette.
|
||
if ((hPalette != NULL) && ((HWND)wParam != hWnd)) {
|
||
// Select the palette into the device context
|
||
SelectPalette(hDC, hPalette, FALSE);
|
||
|
||
// Map entries to system palette
|
||
RealizePalette(hDC);
|
||
|
||
// Remap the current colors to the newly realized palette
|
||
UpdateColors(hDC);
|
||
return 0;
|
||
|
||
}
|
||
break;
|
||
|
||
case WM_MOUSEWHEEL:
|
||
{
|
||
// Pobieramy informację o tym, jak mocno obrócono kółko
|
||
int zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
|
||
|
||
// Zmieniamy dystans kamery (podzielone przez 120, bo tyle wynosi jeden "skok" scrolla)
|
||
CameraHeight -= (float)zDelta * 0.1f;
|
||
|
||
// Ograniczamy zoom, żeby nie wejść kamerą "w łazik" ani nie odlecieć w kosmos
|
||
if (CameraHeight < MinDistance) CameraHeight = MinDistance;
|
||
if (CameraHeight > MaxDistance) CameraHeight = MaxDistance;
|
||
|
||
// Odświeżamy okno
|
||
InvalidateRect(hWnd, NULL, FALSE);
|
||
}
|
||
break;
|
||
|
||
case WM_KEYUP:
|
||
|
||
switch (wParam) {
|
||
|
||
case 'W':
|
||
keyWPressed = false;
|
||
break;
|
||
|
||
case 'S':
|
||
keySPressed = false;
|
||
break;
|
||
|
||
case 'A':
|
||
keyAPressed = false;
|
||
break;
|
||
|
||
case 'D':
|
||
keyDPressed = false;
|
||
break;
|
||
case 112: // F1 - Widok z pierwszej osoby (FPV)
|
||
fpv_view = !fpv_view;
|
||
if (fpv_view) panoramic_view = false; // Wyłącz panoramę, jeśli włączasz FPV
|
||
break;
|
||
// Obsługa innych klawiszy
|
||
|
||
}
|
||
break;
|
||
|
||
case WM_KEYDOWN:
|
||
|
||
switch (wParam) {
|
||
|
||
case VK_UP:
|
||
xRot -= 5.0f;
|
||
break;
|
||
|
||
case VK_DOWN:
|
||
xRot += 5.0f;
|
||
break;
|
||
|
||
case VK_LEFT:
|
||
yRot -= 5.0f;
|
||
break;
|
||
|
||
case VK_RIGHT:
|
||
yRot += 5.0f;
|
||
break;
|
||
|
||
case 'Q':
|
||
zRot += 5.0f;
|
||
break;
|
||
|
||
case 'E':
|
||
zRot -= 5.0f;
|
||
break;
|
||
|
||
case 'R':
|
||
xRot = 0;
|
||
yRot = 0;
|
||
zRot = 0;
|
||
break;
|
||
|
||
case ' ': // 32
|
||
polygonmode = !polygonmode;
|
||
if (polygonmode) timestampedCout("Uwaga! Tryb wireframe jest niewydajny i powinien sluzyc tylko do debugowania!");
|
||
break;
|
||
case 'K':
|
||
Kolizja = !Kolizja;
|
||
break;
|
||
|
||
case 'W':
|
||
keyWPressed = true;
|
||
break;
|
||
|
||
case 'S':
|
||
keySPressed = true;
|
||
break;
|
||
|
||
case 'A':
|
||
keyAPressed = true;
|
||
break;
|
||
|
||
case 'D':
|
||
keyDPressed = true;
|
||
break;
|
||
|
||
// case 114: // F3
|
||
// monitormode = !monitormode;
|
||
// if (monitormode) {
|
||
// monitormodehelper = std::time(nullptr) - 1;
|
||
// timestampedCout("Wlaczono tryb monitorowania wydajnosci.");
|
||
// }
|
||
// if (!monitormode) timestampedCout("Wylaczono tryb monitorowania wydajnosci.");
|
||
// break;
|
||
|
||
case 116: // F5 włącza widok panoramiczny
|
||
panoramic_view = !panoramic_view;
|
||
break;
|
||
|
||
case 16: // Shift również
|
||
panoramic_view = !panoramic_view;
|
||
break;
|
||
|
||
case 8: // Backspace czyści postęp
|
||
nadpiszNowaSiatke(biezacy_wzor);
|
||
break;
|
||
|
||
default:
|
||
timestampedCout("Nacisnieto nierozpoznany klawisz: " << (int)wParam);
|
||
}
|
||
|
||
xRot = (const int)xRot % 360;
|
||
yRot = (const int)yRot % 360;
|
||
zRot = (const int)zRot % 360;
|
||
|
||
InvalidateRect(hWnd, NULL, FALSE);
|
||
break;
|
||
|
||
// A menu command
|
||
case WM_COMMAND:
|
||
|
||
switch (LOWORD(wParam)) {
|
||
|
||
// Exit the program
|
||
case ID_FILE_EXIT:
|
||
DestroyWindow(hWnd);
|
||
break;
|
||
|
||
// Display the about box
|
||
case ID_HELP_ABOUT:
|
||
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG_ABOUT), hWnd, (DLGPROC)AboutDlgProc);
|
||
break;
|
||
|
||
}
|
||
break;
|
||
|
||
case WM_TIMER:
|
||
|
||
|
||
break;
|
||
|
||
default: // Passes it on if unproccessed
|
||
return (DefWindowProc(hWnd, message, wParam, lParam));
|
||
}
|
||
|
||
return (0L);
|
||
}
|
||
|
||
// Dialog procedure.
|
||
BOOL APIENTRY AboutDlgProc(HWND hDlg, UINT message, UINT wParam, LONG lParam) {
|
||
|
||
switch (message) {
|
||
// Initialize the dialog box
|
||
case WM_INITDIALOG:
|
||
int i;
|
||
GLenum glError;
|
||
|
||
// glGetString demo
|
||
SetDlgItemText(hDlg, IDC_OPENGL_VENDOR, reinterpret_cast<LPCSTR>(glGetString(GL_VENDOR)));
|
||
SetDlgItemText(hDlg, IDC_OPENGL_RENDERER, (LPCSTR)glGetString(GL_RENDERER));
|
||
SetDlgItemText(hDlg, IDC_OPENGL_VERSION, (LPCSTR)glGetString(GL_VERSION));
|
||
SetDlgItemText(hDlg, IDC_OPENGL_EXTENSIONS, (LPCSTR)glGetString(GL_EXTENSIONS));
|
||
|
||
// gluGetString demo
|
||
SetDlgItemText(hDlg, IDC_GLU_VERSION, (LPCSTR)gluGetString(GLU_VERSION));
|
||
SetDlgItemText(hDlg, IDC_GLU_EXTENSIONS, (LPCSTR)gluGetString(GLU_EXTENSIONS));
|
||
|
||
|
||
// Display any recent error messages
|
||
i = 0;
|
||
do {
|
||
glError = glGetError();
|
||
SetDlgItemText(hDlg, IDC_ERROR1 + i, (LPCSTR)gluErrorString(glError));
|
||
i++;
|
||
} while (i < 6 && glError != GL_NO_ERROR);
|
||
|
||
|
||
return (TRUE);
|
||
|
||
break;
|
||
|
||
// Process command messages
|
||
case WM_COMMAND:
|
||
|
||
// Validate and Make the changes
|
||
if (LOWORD(wParam) == IDOK) EndDialog(hDlg, TRUE);
|
||
break;
|
||
|
||
// Closed from sysbox
|
||
case WM_CLOSE:
|
||
|
||
EndDialog(hDlg, TRUE);
|
||
break;
|
||
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
void DisableQuickEdit() {
|
||
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
|
||
DWORD prev_mode;
|
||
GetConsoleMode(hInput, &prev_mode);
|
||
|
||
// Wyłączamy opcję ENABLE_QUICK_EDIT_MODE oraz ENABLE_INSERT_MODE
|
||
SetConsoleMode(hInput, prev_mode & ~ENABLE_QUICK_EDIT_MODE & ~ENABLE_INSERT_MODE);
|
||
}
|
||
// Funkcja tworząca macierz cienia (Shadow Matrix)
|
||
// groundplane: równanie płaszczyzny (Ax + By + Cz + D = 0)
|
||
// lightpos: pozycja światła
|
||
void MakeShadowMatrix(GLfloat shadowMat[16], GLfloat groundplane[4], GLfloat lightpos[4])
|
||
{
|
||
GLfloat dot;
|
||
|
||
// Iloczyn skalarny normalnej płaszczyzny i wektora światła
|
||
dot = groundplane[0] * lightpos[0] +
|
||
groundplane[1] * lightpos[1] +
|
||
groundplane[2] * lightpos[2] +
|
||
groundplane[3] * lightpos[3];
|
||
|
||
shadowMat[0] = dot - lightpos[0] * groundplane[0];
|
||
shadowMat[4] = 0.f - lightpos[0] * groundplane[1];
|
||
shadowMat[8] = 0.f - lightpos[0] * groundplane[2];
|
||
shadowMat[12] = 0.f - lightpos[0] * groundplane[3];
|
||
|
||
shadowMat[1] = 0.f - lightpos[1] * groundplane[0];
|
||
shadowMat[5] = dot - lightpos[1] * groundplane[1];
|
||
shadowMat[9] = 0.f - lightpos[1] * groundplane[2];
|
||
shadowMat[13] = 0.f - lightpos[1] * groundplane[3];
|
||
|
||
shadowMat[2] = 0.f - lightpos[2] * groundplane[0];
|
||
shadowMat[6] = 0.f - lightpos[2] * groundplane[1];
|
||
shadowMat[10] = dot - lightpos[2] * groundplane[2];
|
||
shadowMat[14] = 0.f - lightpos[2] * groundplane[3];
|
||
|
||
shadowMat[3] = 0.f - lightpos[3] * groundplane[0];
|
||
shadowMat[7] = 0.f - lightpos[3] * groundplane[1];
|
||
shadowMat[11] = 0.f - lightpos[3] * groundplane[2];
|
||
shadowMat[15] = dot - lightpos[3] * groundplane[3];
|
||
} |