Compare commits
2 Commits
780e852596
...
233d4189d1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
233d4189d1 | ||
|
|
ffa5a929df |
@@ -1,25 +1,40 @@
|
|||||||
#include <iostream>
|
#pragma once // Zabezpieczenie przed wielokrotnym dołączeniem
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
class FPSCounter {
|
class FPSCounter {
|
||||||
public:
|
public:
|
||||||
FPSCounter() : frameCount(0), lastTime(std::chrono::high_resolution_clock::now()) {}
|
FPSCounter() :
|
||||||
|
frameCount(0),
|
||||||
|
currentFPS(0.0),
|
||||||
|
currentFrameTime(0.0),
|
||||||
|
lastTime(std::chrono::high_resolution_clock::now()) {
|
||||||
|
}
|
||||||
|
|
||||||
void update() {
|
// Zwraca true, jeśli minęła sekunda i zaktualizowano dane
|
||||||
|
bool update() {
|
||||||
frameCount++;
|
frameCount++;
|
||||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||||
std::chrono::duration<double> elapsed = currentTime - lastTime;
|
std::chrono::duration<double> elapsed = currentTime - lastTime;
|
||||||
|
|
||||||
// Aktualizujemy FPS co 1 sekundê
|
|
||||||
if (elapsed.count() >= 1.0) {
|
if (elapsed.count() >= 1.0) {
|
||||||
double fps = frameCount / elapsed.count();
|
currentFPS = frameCount / elapsed.count();
|
||||||
std::cout << "FPS: " << fps << "\n";
|
// Obliczamy czas klatki w ms
|
||||||
|
currentFrameTime = 1000.0 / (currentFPS == 0 ? 1 : currentFPS);
|
||||||
|
|
||||||
frameCount = 0;
|
frameCount = 0;
|
||||||
lastTime = currentTime;
|
lastTime = currentTime;
|
||||||
|
return true; // Zgłaszamy, że dane się zmieniły
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- TEGO BRAKOWAŁO W TWOIM KODZIE ---
|
||||||
|
double getFPS() const { return currentFPS; }
|
||||||
|
double getFrameTime() const { return currentFrameTime; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int frameCount;
|
long long frameCount;
|
||||||
|
double currentFPS; // Przechowuje ostatnio obliczone FPS
|
||||||
|
double currentFrameTime; // Przechowuje czas klatki
|
||||||
std::chrono::time_point<std::chrono::high_resolution_clock> lastTime;
|
std::chrono::time_point<std::chrono::high_resolution_clock> lastTime;
|
||||||
};
|
};
|
||||||
72
Logger.hpp
Normal file
72
Logger.hpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <queue>
|
||||||
|
#include <atomic>
|
||||||
|
#include <sstream> // <--- TO JEST NIEZBĘDNE
|
||||||
|
|
||||||
|
class AsyncLogger {
|
||||||
|
public:
|
||||||
|
static AsyncLogger& getInstance() {
|
||||||
|
static AsyncLogger instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void log(const std::string& message) {
|
||||||
|
std::lock_guard<std::mutex> lock(queueMutex);
|
||||||
|
logQueue.push(message);
|
||||||
|
cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
if (running) return;
|
||||||
|
running = true;
|
||||||
|
loggingThread = std::thread(&AsyncLogger::processQueue, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() {
|
||||||
|
running = false;
|
||||||
|
cv.notify_one();
|
||||||
|
if (loggingThread.joinable()) {
|
||||||
|
loggingThread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AsyncLogger() : running(false) {}
|
||||||
|
~AsyncLogger() { stop(); }
|
||||||
|
|
||||||
|
void processQueue() {
|
||||||
|
while (running || !logQueue.empty()) {
|
||||||
|
std::unique_lock<std::mutex> lock(queueMutex);
|
||||||
|
cv.wait(lock, [this] { return !logQueue.empty() || !running; });
|
||||||
|
|
||||||
|
while (!logQueue.empty()) {
|
||||||
|
std::string msg = logQueue.front();
|
||||||
|
logQueue.pop();
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
std::cout << msg << std::endl;
|
||||||
|
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread loggingThread;
|
||||||
|
std::mutex queueMutex;
|
||||||
|
std::condition_variable cv;
|
||||||
|
std::queue<std::string> logQueue;
|
||||||
|
std::atomic<bool> running;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- POPRAWIONE MAKRO ---
|
||||||
|
// Tworzy tymczasowy strumień (ostringstream), który "rozumie" operator <<
|
||||||
|
#define LOG(stream_args) { \
|
||||||
|
std::ostringstream ss; \
|
||||||
|
ss << stream_args; \
|
||||||
|
AsyncLogger::getInstance().log(ss.str()); \
|
||||||
|
}
|
||||||
@@ -138,6 +138,7 @@
|
|||||||
<ClInclude Include="fabula.hpp" />
|
<ClInclude Include="fabula.hpp" />
|
||||||
<ClInclude Include="lazik.hpp" />
|
<ClInclude Include="lazik.hpp" />
|
||||||
<ClInclude Include="loadOBJ.h" />
|
<ClInclude Include="loadOBJ.h" />
|
||||||
|
<ClInclude Include="Logger.hpp" />
|
||||||
<ClInclude Include="plane.hpp" />
|
<ClInclude Include="plane.hpp" />
|
||||||
<ClInclude Include="RESOURCE.H" />
|
<ClInclude Include="RESOURCE.H" />
|
||||||
<ClInclude Include="shader.hpp" />
|
<ClInclude Include="shader.hpp" />
|
||||||
|
|||||||
@@ -80,6 +80,9 @@
|
|||||||
<ClInclude Include="teksturowane.hpp">
|
<ClInclude Include="teksturowane.hpp">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Logger.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="glfw3.dll">
|
<None Include="glfw3.dll">
|
||||||
|
|||||||
120
main.cpp
120
main.cpp
@@ -37,6 +37,9 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include "teksturowane.hpp"
|
#include "teksturowane.hpp"
|
||||||
#include "fabula.hpp"
|
#include "fabula.hpp"
|
||||||
|
#include "GL/wglew.h"
|
||||||
|
#include "Logger.hpp"
|
||||||
|
|
||||||
|
|
||||||
using namespace glm;
|
using namespace glm;
|
||||||
|
|
||||||
@@ -48,13 +51,16 @@ using namespace glm;
|
|||||||
|
|
||||||
//using namespace std;
|
//using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HPALETTE hPalette = NULL;
|
HPALETTE hPalette = NULL;
|
||||||
|
|
||||||
// Application name and instance storage
|
// Application name and instance storage
|
||||||
static LPCTSTR lpszAppName = "grafikaKBT";
|
static LPCTSTR lpszAppName = "grafikaKBT";
|
||||||
static HINSTANCE hInstance;
|
static HINSTANCE hInstance;
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
|
///////////////////////
|
||||||
|
void DisableQuickEdit();
|
||||||
// Rotation amounts
|
// Rotation amounts
|
||||||
static GLfloat xRot = 0.0f;
|
static GLfloat xRot = 0.0f;
|
||||||
static GLfloat yRot = 0.0f;
|
static GLfloat yRot = 0.0f;
|
||||||
@@ -86,23 +92,30 @@ bool panoramic_view = 0;
|
|||||||
//Zmienne do ruchu ##############################################^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
//Zmienne do ruchu ##############################################^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
FPSCounter fpsCounter;
|
FPSCounter fpsCounter;
|
||||||
|
|
||||||
static const int targetFPS = 250; // Celowany FPS
|
static const int targetFPS = 444; // Celowany FPS
|
||||||
//Fps counter
|
//Fps counter
|
||||||
static void LimitFPS(int targetFPS) {
|
static void LimitFPS(int targetFPS) {
|
||||||
static auto lastTime = std::chrono::high_resolution_clock::now();
|
static auto lastTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
// Obliczamy czas na jedną klatkę
|
||||||
|
double targetFrameDuration = 1.0 / targetFPS;
|
||||||
|
|
||||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||||
std::chrono::duration<double> elapsed = currentTime - lastTime;
|
std::chrono::duration<double> elapsed = currentTime - lastTime;
|
||||||
|
|
||||||
// Obliczamy czas na jedną klatkę
|
// --- CZYSTA PĘTLA (Busy Wait) ---
|
||||||
double frameTime = 1.0 / targetFPS; // Czas na jedną klatkę w sekundach
|
// Usunęliśmy sleep_for, bo w Windows jest zbyt nieprecyzyjny dla FPS > 64.
|
||||||
double timeToWait = frameTime - elapsed.count(); // Obliczamy czas do czekania
|
// Teraz procesor będzie pracował na 100% jednego wątku, ale FPS będzie idealny.
|
||||||
|
while (elapsed.count() < targetFrameDuration) {
|
||||||
|
// Tylko aktualizujemy czas, nic więcej.
|
||||||
|
// Jeśli chcesz trochę odciążyć CPU, można użyć instrukcji procesora 'pause',
|
||||||
|
// ale w standardowym C++ po prostu pusta pętla z pomiarem czasu jest najpewniejsza.
|
||||||
|
|
||||||
if (timeToWait > 0.0) {
|
currentTime = std::chrono::high_resolution_clock::now();
|
||||||
// Jeśli czas do czekania jest większy niż 0, to śpimy przez tę wartość
|
elapsed = currentTime - lastTime;
|
||||||
std::this_thread::sleep_for(std::chrono::duration<double>(timeToWait));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lastTime = currentTime; // Zaktualizuj czas dla następnej iteracji
|
lastTime = std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Kolizja = false;
|
bool Kolizja = false;
|
||||||
@@ -506,6 +519,14 @@ static void SetupRC() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
timestampedCout("Zainicjalizowano GLEW.");
|
timestampedCout("Zainicjalizowano GLEW.");
|
||||||
|
// Sprawdź czy rozszerzenie jest dostępne i wyłącz V-Sync
|
||||||
|
if (wglewIsSupported("WGL_EXT_swap_control")) {
|
||||||
|
wglSwapIntervalEXT(0); // 0 = WYŁĄCZ V-Sync (nielimitowane FPS)
|
||||||
|
timestampedCout("V-Sync wylaczony (unlocked FPS).");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
timestampedCout("Brak obslugi WGL_EXT_swap_control - nie mozna programowo wylaczyc V-Sync.");
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize GLFW3
|
// Initialize GLFW3
|
||||||
timestampedCout("Inicjalizowanie GLFW3...");
|
timestampedCout("Inicjalizowanie GLFW3...");
|
||||||
@@ -520,7 +541,7 @@ static void SetupRC() {
|
|||||||
timestampedCout("Ladowanie modelu mapki...");
|
timestampedCout("Ladowanie modelu mapki...");
|
||||||
mapa.loadModel();
|
mapa.loadModel();
|
||||||
|
|
||||||
glfwSwapInterval(1);
|
glfwSwapInterval(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -742,64 +763,64 @@ void static CreateConsole() {
|
|||||||
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||||
|
|
||||||
CreateConsole();
|
CreateConsole();
|
||||||
MSG msg; // Windows message structure
|
DisableQuickEdit();
|
||||||
WNDCLASS wc{}; // Windows class structure
|
AsyncLogger::getInstance().start();
|
||||||
HWND hWnd; // Storeage for window handle
|
MSG msg;
|
||||||
|
WNDCLASS wc{};
|
||||||
|
HWND hWnd;
|
||||||
|
|
||||||
hInstance = hInst;
|
hInstance = hInst;
|
||||||
|
|
||||||
// Register Window style
|
// Rejestracja klasy okna
|
||||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // DODANO CS_OWNDC - ważne dla OpenGL
|
||||||
wc.lpfnWndProc = (WNDPROC)WndProc;
|
wc.lpfnWndProc = (WNDPROC)WndProc;
|
||||||
wc.cbClsExtra = 0;
|
wc.cbClsExtra = 0;
|
||||||
wc.cbWndExtra = 0;
|
wc.cbWndExtra = 0;
|
||||||
wc.hInstance = hInstance;
|
wc.hInstance = hInstance;
|
||||||
wc.hIcon = NULL;
|
wc.hIcon = NULL;
|
||||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
|
|
||||||
// No need for background brush for OpenGL window
|
|
||||||
wc.hbrBackground = NULL;
|
wc.hbrBackground = NULL;
|
||||||
|
|
||||||
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
|
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
|
||||||
wc.lpszClassName = lpszAppName;
|
wc.lpszClassName = lpszAppName;
|
||||||
|
|
||||||
// Register the window class
|
|
||||||
if (RegisterClass(&wc) == 0) return FALSE;
|
if (RegisterClass(&wc) == 0) return FALSE;
|
||||||
|
|
||||||
|
|
||||||
// Create the main application window
|
|
||||||
hWnd = CreateWindow(
|
hWnd = CreateWindow(
|
||||||
lpszAppName,
|
lpszAppName, lpszAppName,
|
||||||
lpszAppName,
|
|
||||||
|
|
||||||
// OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
|
|
||||||
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
||||||
|
50, 50, 800, 800,
|
||||||
|
NULL, NULL, hInstance, NULL);
|
||||||
|
|
||||||
// Window position and size
|
|
||||||
50, 50,
|
|
||||||
800, 800,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
hInstance,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
// If window was not created, quit
|
|
||||||
if (hWnd == NULL) return FALSE;
|
if (hWnd == NULL) return FALSE;
|
||||||
|
|
||||||
|
// --- POPRAWKA 1: Pobierz HDC raz ---
|
||||||
|
HDC hDC = GetDC(hWnd);
|
||||||
|
|
||||||
const WORD ID_TIMER = 1;
|
const WORD ID_TIMER = 1;
|
||||||
SetTimer(hWnd, ID_TIMER, 100, NULL);
|
SetTimer(hWnd, ID_TIMER, 100, NULL);
|
||||||
|
|
||||||
// Display the window
|
|
||||||
ShowWindow(hWnd, SW_SHOW);
|
ShowWindow(hWnd, SW_SHOW);
|
||||||
UpdateWindow(hWnd);
|
UpdateWindow(hWnd);
|
||||||
|
|
||||||
// Process application messages until the application closes
|
ZeroMemory(&msg, sizeof(msg));
|
||||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
while (msg.message != WM_QUIT) {
|
||||||
TranslateMessage(&msg);
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
DispatchMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RenderScene();
|
||||||
|
|
||||||
|
// --- POPRAWKA 2: Używaj zapisanego hDC, a nie pobieraj nowego ---
|
||||||
|
SwapBuffers(hDC);
|
||||||
|
LOG("FPS: " << fpsCounter.getFPS() << " | Czas: " << fpsCounter.getFrameTime() << "ms");
|
||||||
|
LimitFPS(targetFPS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- POPRAWKA 3: Zwolnij HDC przy zamykaniu ---
|
||||||
|
ReleaseDC(hWnd, hDC);
|
||||||
|
|
||||||
return msg.wParam;
|
return msg.wParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -907,6 +928,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
// Tell the application to terminate after the window
|
// Tell the application to terminate after the window
|
||||||
// is gone.
|
// is gone.
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
|
AsyncLogger::getInstance().stop();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Window is resized.
|
// Window is resized.
|
||||||
@@ -920,15 +942,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
// The painting function. This message sent by Windows
|
// The painting function. This message sent by Windows
|
||||||
// whenever the screen needs updating.
|
// whenever the screen needs updating.
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
LimitFPS(targetFPS);
|
|
||||||
// Call OpenGL drawing code
|
|
||||||
RenderScene();
|
|
||||||
|
|
||||||
SwapBuffers(hDC);
|
ValidateRect(hWnd, NULL);
|
||||||
|
|
||||||
// Validate the newly painted client area
|
|
||||||
if (!monitormode) ValidateRect(hWnd, NULL);
|
|
||||||
else InvalidateRect(hWnd, NULL, FALSE);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_QUERYNEWPALETTE:
|
case WM_QUERYNEWPALETTE:
|
||||||
@@ -1125,9 +1141,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
|
|
||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
|
|
||||||
RenderScene();
|
|
||||||
SwapBuffers(hDC);
|
|
||||||
ValidateRect(hWnd, NULL);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // Passes it on if unproccessed
|
default: // Passes it on if unproccessed
|
||||||
@@ -1187,3 +1201,11 @@ BOOL APIENTRY AboutDlgProc(HWND hDlg, UINT message, UINT wParam, LONG lParam) {
|
|||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
void DisableQuickEdit() {
|
||||||
|
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
DWORD prev_mode;
|
||||||
|
GetConsoleMode(hInput, &prev_mode);
|
||||||
|
|
||||||
|
// Wyłączamy opcję ENABLE_QUICK_EDIT_MODE oraz ENABLE_INSERT_MODE
|
||||||
|
SetConsoleMode(hInput, prev_mode & ~ENABLE_QUICK_EDIT_MODE & ~ENABLE_INSERT_MODE);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user