#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) 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, 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& fences) { for (const auto& fence: fences) { if (CheckFenceCollision(roverXMin, roverXMax, roverZMin, roverZMax, fence)) { // Kolizja wykryta z którymś płotem return true; } } return false; // Brak kolizji } static void UpdateRover(const std::vector& fences) { if (keyWPressed) { // Przyspieszanie w przód velocity += acceleration; if (velocity > maxSpeed) velocity = maxSpeed; } else if (keySPressed) { // Przyspieszanie w tył velocity -= acceleration; if (velocity < -maxSpeed) velocity = -maxSpeed; } else { // Hamowanie (wytracanie prędkości z powodu tarcia) 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 żaden z klawiszy A/D nie jest wciśnięty, // to stopniowo spowalniamy rotację (drift) // Mniejsza wartość = dłuższy drift 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; } } // 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) { if (CheckAllFencesCollision(roverZMin, roverZMax, roverXMin, roverXMax, fences)) { // Jeśli jest kolizja, zatrzymujemy łazik // cout << "Kolizja podczas ruchu!\n"; velocity = 0.0f; } 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> 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) { //cout << "Kolizja podczas obrotu!\n"; rotationVelocity = 0.0f; // Zatrzymujemy obrót } 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 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); // Widok panoramiczny (SHIFT/F5) if (panoramic_view) { // Zwiększ prędkość obrotu oraz tarcie 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 { // Ustaw tarcie i prędkość obrotu na domyślną wartość 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(); // 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: // 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; 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(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; }