Files
grafikaKBT/main.cpp

1184 lines
38 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"
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;
// 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);
void sprawdzPostepGry();
void ustalPozycjeGracza(GLfloat gracz_x, GLfloat gracz_z, short &grid_x, short &grid_z);
void ustawSiatkeNaWzorNieNadpisujacPostepu();
void nadpiszNowaSiatke(short nowy_wzor);
void tworzKratke(unsigned int grid_x, unsigned int grid_z, unsigned short grid_value);
void tworzKratkiZSiatki();
void aktualizujBiezacaKratke(short grid_x, short grid_z);
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;
static const int targetFPS = 250; // Celowany FPS
//Fps counter
static void LimitFPS(int targetFPS) {
static auto lastTime = std::chrono::high_resolution_clock::now();
auto currentTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = currentTime - lastTime;
// Obliczamy czas na jedną klatkę
double frameTime = 1.0 / targetFPS; // Czas na jedną klatkę w sekundach
double timeToWait = frameTime - elapsed.count(); // Obliczamy czas do czekania
if (timeToWait > 0.0) {
// Jeśli czas do czekania jest większy niż 0, to śpimy przez tę wartość
std::this_thread::sleep_for(std::chrono::duration<double>(timeToWait));
}
lastTime = currentTime; // Zaktualizuj czas dla następnej iteracji
}
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)
float CameraHeight = 50.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 płotu w osi Y (nieużywane w kolizji, ale może być pomocne)
GLfloat zc; // Środek płotu w osi Z
GLfloat length; // Długość płotu
GLfloat gruboscY; // Grubość płotu
bool mod_x; // 0 - płot pionowy, 1 - płot poziomy
};
// Funkcja sprawdzająca kolizję z płotem
// Funkcja sprawdzająca kolizję z płotem, uwzględniając wymiary łazika
static bool CheckFenceCollision(float roverXMin, float roverXMax, float roverZMin, float roverZMax, const Plot& plot) {
if (plot.mod_x == 0) { // Płot pionowy (równoległy do osi Z)
float xMin = plot.xc - plot.gruboscY / 2.0f;
float xMax = plot.xc + plot.gruboscY / 2.0f;
float zMin = plot.zc - plot.length / 2.0f;
float zMax = plot.zc + plot.length / 2.0f;
// Sprawdzenie, czy którykolwiek fragment łazika wchodzi w obszar płotu
if (roverXMax >= xMin && roverXMin <= xMax && // Kolizja w osi X
roverZMax >= zMin && roverZMin <= zMax) { // Kolizja w osi Z
return true;
}
}
else { // Płot poziomy (równoległy do osi X)
float xMin = plot.xc - plot.length / 2.0f;
float xMax = plot.xc + plot.length / 2.0f;
float zMin = plot.zc - plot.gruboscY / 2.0f;
float zMax = plot.zc + plot.gruboscY / 2.0f;
// Sprawdzenie, czy którykolwiek fragment łazika wchodzi w obszar płotu
if (roverXMax >= xMin && roverXMin <= xMax && // Kolizja w osi X
roverZMax >= zMin && roverZMin <= zMax) { // Kolizja w osi Z
return true;
}
}
return false;
}
// Funkcja ogólna do sprawdzania kolizji ze wszystkimi płotami
static bool CheckAllFencesCollision(float roverXMin, float roverXMax, float roverZMin, float roverZMax, const std::vector<Plot>& fences) {
for (const auto& fence : fences) {
if (CheckFenceCollision(roverXMin, roverXMax, roverZMin, roverZMax, fence)) {
return true; // Kolizja wykryta z którymś płotem
}
}
return false; // Brak kolizji
}
static void UpdateRover(const std::vector<Plot>& fences) {
// Przyspieszanie w przód
if (keyWPressed) {
velocity += acceleration;
if (velocity > maxSpeed) velocity = maxSpeed;
}
// Przyspieszanie w tył
else if (keySPressed) {
velocity -= acceleration;
if (velocity < -maxSpeed) velocity = -maxSpeed;
}
// Hamowanie (wytracanie prędkości z powodu tarcia)
else {
if (velocity > 0) {
velocity -= friction;
if (velocity < 0) velocity = 0;
}
else if (velocity < 0) {
velocity += friction;
if (velocity > 0) velocity = 0;
}
}
// Obracanie (rotacja z driftowaniem)
if (keyAPressed) {
rotationVelocity += rotationAcceleration;
if (rotationVelocity > maxRotationSpeed) rotationVelocity = maxRotationSpeed;
}
else if (keyDPressed) {
rotationVelocity -= rotationAcceleration;
if (rotationVelocity < -maxRotationSpeed) rotationVelocity = -maxRotationSpeed;
}
else {
// Jeśli żadna z klawiszy A/D nie jest wciśnięta, to stopniowo spowalniamy rotację (drift)
float driftFactor = 0.1f; // Mniejsza wartość = dłuższy drift
if (rotationVelocity > 0) {
rotationVelocity -= rotationFriction * driftFactor;
if (rotationVelocity < 0) rotationVelocity = 0;
}
else if (rotationVelocity < 0) {
rotationVelocity += rotationFriction * driftFactor;
if (rotationVelocity > 0) rotationVelocity = 0;
}
}
// Wyliczenie nowej pozycji na podstawie prędkości
float radRotation = Rotation * GL_PI / 180.0f; // Przeliczamy rotację na radiany
float newSides = Sides - velocity * cos(radRotation); // Nowa pozycja w osi X
float newFoward = Foward - velocity * sin(radRotation); // Nowa pozycja w osi Z
// Wymiary łazika (połówki w osi X i Z)
const float roverHalfWidthX = 19.0f; // 38/2
const float roverHalfLengthZ = 12.0f; // 24/2
// Wyliczenie obszaru zajmowanego przez łazik
float roverXMin = newSides - roverHalfWidthX;
float roverXMax = newSides + roverHalfWidthX;
float roverZMin = newFoward - roverHalfLengthZ;
float roverZMax = newFoward + roverHalfLengthZ;
// Sprawdzanie kolizji przed aktualizacją pozycji
if (!Kolizja == true) {
if (CheckAllFencesCollision(roverZMin, roverZMax, roverXMin, roverXMax, fences)) {
// Jeśli jest kolizja, zatrzymujemy łazik
velocity = 0.0f;
//cout << "Kolizja podczas ruchu\n";
}
else {
// Jeśli brak kolizji, aktualizujemy pozycję
Sides = newSides;
Foward = newFoward;
}
// Sprawdzanie kolizji podczas obrotu
if (rotationVelocity != 0.0f) {
// Wyliczamy nową rotację
float newRotation = Rotation + rotationVelocity;
float radNewRotation = newRotation * GL_PI / 180.0f;
// Obracamy narożniki łazika
std::vector<std::pair<float, float>> corners(4);
corners[0] = {Sides - roverHalfWidthX, Foward - roverHalfLengthZ}; // Lewy dolny
corners[1] = {Sides + roverHalfWidthX, Foward - roverHalfLengthZ}; // Prawy dolny
corners[2] = {Sides - roverHalfWidthX, Foward + roverHalfLengthZ}; // Lewy górny
corners[3] = {Sides + roverHalfWidthX, Foward + roverHalfLengthZ}; // Prawy górny
bool collisionDetected = false;
// Obracamy wszystkie narożniki
for (auto& corner : corners) {
float x = corner.first;
float z = corner.second;
corner.first = Sides + (x - Sides) * cos(radNewRotation) - (z - Foward) * sin(radNewRotation);
corner.second = Foward + (x - Sides) * sin(radNewRotation) + (z - Foward) * cos(radNewRotation);
// Sprawdzamy kolizję na podstawie obróconych narożników
if (CheckAllFencesCollision(corner.first, corner.first, corner.second, corner.second, fences)) {
collisionDetected = true;
break;
}
if (CheckAllFencesCollision( corner.second, corner.second, corner.first, corner.first, fences)) {
collisionDetected = true;
break;
}
}
if (collisionDetected) {
rotationVelocity = 0.0f; // Zatrzymujemy obrót
//cout << "Kolizja podczas obrotu\n";
} else {
// Aktualizujemy rotację, jeśli nie ma kolizji
Rotation = newRotation;
if (Rotation >= 360.0f) Rotation -= 360.0f;
if (Rotation < 0.0f) Rotation += 360.0f;
}
}
}
else {
// Jeśli kolizje są wyłączone, aktualizujemy wszystko bez sprawdzania
Sides = newSides;
Foward = newFoward;
Rotation += rotationVelocity;
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) {
GLfloat nRange = 100.0f;
//GLfloat fAspect;
// Prevent a divide by zero
if (h == 0) h = 1;
lastWidth = w;
lastHeight = h;
//fAspect = (GLfloat)w / (GLfloat)h;
// Set Viewport to window dimensions
glViewport(0, 0, w, h);
// Reset coordinate system
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// // Establish clipping volume (left, right, bottom, top, near, far)
// if (w <= h) glOrtho(-nRange, nRange, -nRange * h / w, nRange * h / w, -nRange, nRange);
// else glOrtho(-nRange * w / h, nRange * w / h, -nRange, nRange, -nRange, nRange);
// Establish clipping volume (left, right, bottom, top, near, far)
if (w <= h) glOrtho(-nRange, nRange, -nRange * h / w, nRange * h / w, -20 * nRange, 20 * nRange);
else glOrtho(-nRange * w / h, nRange * w / h, -nRange, nRange, -20 * nRange, 20 * nRange);
// Establish perspective:
/*
gluPerspective(60.0f, fAspect, 1.0, 400);
*/
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() {
// Light values and coordinates
GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f };
GLfloat diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f };
GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };
// Multiple light positions (for light coming from all sides)
GLfloat lightPos1[] = { 50.0f, -100.0f, 50.0f, 1.0f }; // Light 0 position
GLfloat lightPos2[] = { -50.0f, -100.0f, 50.0f, 1.0f }; // Light 1 position
GLfloat lightPos3[] = { 50.0f, -100.0f, -50.0f, 1.0f }; // Light 2 position
GLfloat lightPos4[] = { -50.0f, -100.0f, -50.0f, 1.0f }; // Light 3 position
glEnable(GL_DEPTH_TEST); // Hidden surface removal
glFrontFace(GL_CCW); // Counter clockwise polygons face out
glDepthFunc(GL_LESS);
// Enable lighting
glEnable(GL_LIGHTING);
// Setup and enable light 0
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos1);
glEnable(GL_LIGHT0);
// Setup and enable light 1
glLightfv(GL_LIGHT1, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
glLightfv(GL_LIGHT1, GL_POSITION, lightPos2);
glEnable(GL_LIGHT1);
// Setup and enable light 2
glLightfv(GL_LIGHT2, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT2, GL_SPECULAR, specular);
glLightfv(GL_LIGHT2, GL_POSITION, lightPos3);
glEnable(GL_LIGHT2);
// Setup and enable light 3
// glLightfv(GL_LIGHT3, GL_AMBIENT, ambientLight);
// glLightfv(GL_LIGHT3, GL_DIFFUSE, diffuseLight);
// glLightfv(GL_LIGHT3, GL_SPECULAR, specular);
// glLightfv(GL_LIGHT3, GL_POSITION, lightPos4);
// glEnable(GL_LIGHT3);
// Enable color tracking
glEnable(GL_COLOR_MATERIAL);
// Set Material properties to follow glColor values
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
// All materials hereafter have full specular reflectivity
// with a high shine
GLfloat specref2[] = {0.2f, 0.2f, 0.2f, 0.2f};
glMaterialfv(GL_FRONT, GL_SPECULAR, specref2);
glMateriali(GL_FRONT, GL_SHININESS, 128);
// White background
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// Initialize GLEW
timestampedCout("Inicjalizowanie GLEW...");
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
timestampedCout("Failed to initialize GLEW");
return;
}
timestampedCout("Zainicjalizowano GLEW.");
// Initialize GLFW3
timestampedCout("Inicjalizowanie GLFW3...");
if (!glfwInit()) {
timestampedCout("Failed to initialize GLFW");
}
timestampedCout("Zainicjalizowano GLFW3.");
// Load models
timestampedCout("Ladowanie modelu lazika...");
user.loadModel();
timestampedCout("Ladowanie modelu mapki...");
mapa.loadModel();
glfwSwapInterval(1);
}
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);
// Przywrócenie macierzy widoku
if (panoramic_view) {
maxRotationSpeed = 1.0f;
rotationFriction = 0.5f;
gluLookAt(
Foward, // Pozycja kamery
123, // Wysokość kamery, nie ma znaczenia bo nie mamy perspektywy
Sides - 1.0f, // Kamera wzdłuż osi X i Z, z jakiegoś powodu działa po "- 1.0f"
Foward, 0.0f, Sides, // Punkt patrzenia (łazik)
0.0f, 1.0f, 0.0f // Wektor "góry"
);
} else {
maxRotationSpeed = 0.5f;
rotationFriction = 0.1f;
gluLookAt(
Foward - 50.0f * sin((Rotation + 180.0f) * GL_PI / 180.0f), // Pozycja kamery
CameraHeight / 4, // Wysokość kamery
Sides - 50.0f * cos((Rotation + 180.0f) * GL_PI / 180.0f), // Kamera wzdłuż osi X i Z
Foward, 0.0f, Sides, // Punkt patrzenia (łazik)
0.0f, 1.0f, 0.0f // Wektor "góry"
);
}
// 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();
UpdateRover(fences);
fpsCounter.update();
glPopMatrix();
// std::cout << "X: " << Foward << " Z: " << Sides << " Rotation: " << Rotation << "\n";
// Rysowanie innych obiektów
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
// 1 pole siatki = 90x90m
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();
MSG msg; // Windows message structure
WNDCLASS wc{}; // Windows class structure
HWND hWnd; // Storeage for window handle
hInstance = hInst;
// Register Window style
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// No need for background brush for OpenGL window
wc.hbrBackground = NULL;
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
wc.lpszClassName = lpszAppName;
// Register the window class
if (RegisterClass(&wc) == 0) return FALSE;
// Create the main application window
hWnd = CreateWindow(
lpszAppName,
lpszAppName,
// OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
// Window position and size
50, 50,
800, 800,
NULL,
NULL,
hInstance,
NULL);
// If window was not created, quit
if (hWnd == NULL) return FALSE;
const WORD ID_TIMER = 1;
SetTimer(hWnd, ID_TIMER, 100, NULL);
// Display the window
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
// Process application messages until the application closes
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
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:
// Store the device context
hDC = GetDC(hWnd);
// Select the pixel format
SetDCPixelFormat(hDC);
// Create palette if needed
hPalette = GetOpenGLPalette(hDC);
// Create the rendering context and make it current
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
SetupRC();
glGenTextures(3, &texture[0]); // tworzy obiekt tekstury
// ładuje pierwszy obraz tekstury (płotki):
bitmapData = LoadBitmapFile((char*)"res/img/woodenTextureHighExposure.bmp", &bitmapInfoHeader);
glBindTexture(GL_TEXTURE_2D, texture[0]); // aktywuje obiekt tekstury
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// 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_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
// tworzy obraz tekstury
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmapInfoHeader.biWidth,
bitmapInfoHeader.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);
if (bitmapData) free(bitmapData);
// ładuje drugi obraz tekstury (ziemia):
bitmapData = LoadBitmapFile((char*)"res/img/grass02.bmp", &bitmapInfoHeader);
glBindTexture(GL_TEXTURE_2D, texture[1]); // aktywuje obiekt tekstury
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
// tworzy obraz tekstury
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmapInfoHeader.biWidth,
bitmapInfoHeader.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);
if (bitmapData) free(bitmapData);
// ładuje trzeci obraz tekstury (dach stodoły):
bitmapData = LoadBitmapFile((char*)"res/img/barnroof.bmp", &bitmapInfoHeader);
glBindTexture(GL_TEXTURE_2D, texture[2]); // aktywuje obiekt tekstury
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// tworzy obraz tekstury
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmapInfoHeader.biWidth,
bitmapInfoHeader.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);
if (bitmapData) free(bitmapData);
// ładuje czwarty obraz tekstury (kamienista ściana):
bitmapData = LoadBitmapFile((char*)"res/img/brickwall.bmp", &bitmapInfoHeader);
glBindTexture(GL_TEXTURE_2D, texture[3]); // aktywuje obiekt tekstury
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// tworzy obraz tekstury
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmapInfoHeader.biWidth,
bitmapInfoHeader.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);
if (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);
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:
LimitFPS(targetFPS);
// Call OpenGL drawing code
RenderScene();
SwapBuffers(hDC);
// Validate the newly painted client area
if (!monitormode) ValidateRect(hWnd, NULL);
else InvalidateRect(hWnd, NULL, FALSE);
//break;
// Limit FPS
// Uaktualniaj FPS
// Ogranicz FPS
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_KEYUP:
switch (wParam) {
case 'W':
keyWPressed = false;
break;
case 'S':
keySPressed = false;
break;
case 'A':
keyAPressed = false;
break;
case 'D':
keyDPressed = false;
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:
RenderScene();
SwapBuffers(hDC);
ValidateRect(hWnd, NULL);
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;
}