#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 // Window defines #include "GL/glew.h" // Dołączony jako pliki glew.c i glew.h //#include // OpenGL #include // biblioteka GLU; program kompiluje się bez niej, ale w celu uniknięcia w przyszłości niespodzianek to została dołączona #include // Define for sqrt //#include #include #include "RESOURCE.H" // About box resource identifiers. #include "loadOBJ.h" #include "lazik.hpp" #include "plane.hpp" //#include #include "GL/glm/glm.hpp" #include "GL/glfw3.h" #include #include "timeh.hpp" #include "texture.hpp" #include "shader.hpp" #include "FPSCounter.cpp" #include #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); 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 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(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) 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& fences) { for (const auto& fence : fences) { if (CheckFenceCollision(rXMin, rXMax, rZMin, rZMax, fence)) { return true; } } return false; } static void UpdateRover(const std::vector& fences) { // --- 1. OBSŁUGA PRZYSPIESZENIA (W / S) --- if (keyWPressed) { velocity += acceleration; if (velocity > maxSpeed) velocity = maxSpeed; } else if (keySPressed) { velocity -= acceleration; if (velocity < -maxSpeed) velocity = -maxSpeed; } else { // Hamowanie (tarcie) if (velocity > 0) { velocity -= friction; if (velocity < 0) velocity = 0; } else if (velocity < 0) { velocity += friction; if (velocity > 0) velocity = 0; } } // --- 2. OBSŁUGA OBROTU (A / D) --- if (keyAPressed) { rotationVelocity += rotationAcceleration; if (rotationVelocity > maxRotationSpeed) rotationVelocity = maxRotationSpeed; } else if (keyDPressed) { rotationVelocity -= rotationAcceleration; if (rotationVelocity < -maxRotationSpeed) rotationVelocity = -maxRotationSpeed; } else { // Driftowanie (wytracanie rotacji) float driftFactor = 0.1f; if (rotationVelocity > 0) { rotationVelocity -= rotationFriction * driftFactor; if (rotationVelocity < 0) rotationVelocity = 0; } else if (rotationVelocity < 0) { rotationVelocity += rotationFriction * driftFactor; if (rotationVelocity > 0) rotationVelocity = 0; } } // --- 3. LOGIKA ODWRÓCENIA SKRĘTU PRZY COFANIU --- // Jeśli prędkość jest ujemna, odwracamy wpływ rotationVelocity na kąt, // aby klawisz D zawsze kierował pojazd w prawo względem kamery. float actualRotationStep = rotationVelocity; if (velocity < 0.0f) { actualRotationStep = -rotationVelocity; } // --- 4. WYLICZENIE NOWEJ POZYCJI --- float radRotation = Rotation * GL_PI / 180.0f; float newSides = Sides - velocity * cos(radRotation); float newFoward = Foward - velocity * 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; } 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) std::vector> 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); if (CheckAllFencesCollision(rotatedX, rotatedX, rotatedZ, rotatedZ, 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 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() { glEnable(GL_MULTISAMPLE); // glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // 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); // 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(); 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: { // 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); 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; 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: 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(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; }