5 Commits

Author SHA1 Message Date
Pc
e04fc59eda chore: main cleanup in new files 2026-02-02 00:33:08 +01:00
Pc
a3e3c8a955 feat: rain +day_&_night 2026-02-01 23:54:22 +01:00
Pc
5e41db643c fix: better values for shadows level and color 2026-01-28 02:57:50 +01:00
Pc
2fbd33901c feat: simple shader rendering 2026-01-28 02:49:27 +01:00
Pc
96b1692434 feat: new light + simple shader function 2026-01-28 02:46:31 +01:00
15 changed files with 1110 additions and 1260 deletions

96
DayNightCycle.hpp Normal file
View File

@@ -0,0 +1,96 @@
#ifndef DAYNIGHTCYCLE_HPP
#define DAYNIGHTCYCLE_HPP
#include "GL/glew.h"
#include <iostream>
class DayNightCycle {
private:
bool isNight;
public:
// Konstruktor - domyślnie startujemy w dzień
DayNightCycle() : isNight(false) {}
// Funkcja przełączająca stan
void toggle() {
isNight = !isNight;
if (isNight) {
std::cout << "Tryb: NOC" << std::endl;
}
else {
std::cout << "Tryb: DZIEN" << std::endl;
}
}
// Zwraca informację czy jest noc (przydatne np. do włączania świateł łazika)
bool isNightMode() const {
return isNight;
}
// Główna funkcja ustawiająca światła i tło
void apply() {
if (isNight) {
// === USTAWIENIA NOCNE ===
// Kolor nieba (Tło) - Ciemny granat/czarny
glClearColor(0.05f, 0.05f, 0.1f, 1.0f);
// GL_LIGHT0 (Księżyc) - Zimne, słabe światło
GLfloat nightAmbient[] = { 0.1f, 0.1f, 0.2f, 1.0f };
GLfloat nightDiffuse[] = { 0.2f, 0.2f, 0.35f, 1.0f }; // Niebieskawy odcień
GLfloat nightSpecular[] = { 0.1f, 0.1f, 0.1f, 1.0f }; // Bardzo słaby połysk
glLightfv(GL_LIGHT0, GL_AMBIENT, nightAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, nightDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, nightSpecular);
// GL_LIGHT1 (Doświetlenie cieni) - Prawie wyłączone w nocy
GLfloat fillAmbient[] = { 0.02f, 0.02f, 0.05f, 1.0f };
GLfloat fillDiffuse[] = { 0.05f, 0.05f, 0.1f, 1.0f };
glLightfv(GL_LIGHT1, GL_AMBIENT, fillAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, fillDiffuse);
// Opcjonalnie: Włączamy gęstą czarną mgłę dla klimatu
glEnable(GL_FOG);
GLfloat fogColor[] = { 0.05f, 0.05f, 0.1f, 1.0f };
glFogfv(GL_FOG_COLOR, fogColor);
glFogi(GL_FOG_MODE, GL_EXP2);
glFogf(GL_FOG_DENSITY, 0.002f); // Gęstość mgły
}
else {
// === USTAWIENIA DZIENNE ===
// Kolor nieba (Tło) - Jasny błękit
glClearColor(0.53f, 0.81f, 0.92f, 1.0f);
// GL_LIGHT0 (Słońce) - Ciepłe, jasne światło
GLfloat dayAmbient[] = { 0.4f, 0.4f, 0.4f, 1.0f };
GLfloat dayDiffuse[] = { 0.9f, 0.9f, 0.8f, 1.0f }; // Lekko żółtawe
GLfloat daySpecular[] = { 0.5f, 0.5f, 0.5f, 1.0f };
glLightfv(GL_LIGHT0, GL_AMBIENT, dayAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, dayDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, daySpecular);
// GL_LIGHT1 (Doświetlenie cieni)
GLfloat fillAmbient[] = { 0.4f, 0.4f, 0.4f, 1.0f };
GLfloat fillDiffuse[] = { 0.3f, 0.3f, 0.4f, 1.0f }; // Niebieskawe cienie
glLightfv(GL_LIGHT1, GL_AMBIENT, fillAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, fillDiffuse);
// Wyłączamy mgłę w dzień (lub ustawiamy bardzo rzadką)
glDisable(GL_FOG);
}
// Pozycję światła ustawiamy taką samą dla obu (wysoko w górze)
// W przyszłości możesz tu zrobić animację przesuwania się słońca
GLfloat lightPos[] = { 100.0f, 150.0f, 100.0f, 0.0f }; // 0.0f na końcu = światło kierunkowe
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
}
};
#endif

39
Global.cpp Normal file
View File

@@ -0,0 +1,39 @@
#include "Global.h"
// Inicjalizacja zmiennych
float deltaTime = 0.0f;
FPSCounter fpsCounter;
bool panoramic_view = false;
bool fpv_view = false;
int polygonmode = 0;
bool Kolizja = false;
short biezacy_wzor = 0;
float CameraHeight = 150.0f;
float xRot = 0.0f;
float yRot = 0.0f;
float zRot = 0.0f;
float Foward = 45.0f;
float Sides = -45.0f;
float Rotation = 270.0f;
float velocity = 0.0f;
float rotationVelocity = 0.0f;
bool keyWPressed = false;
bool keySPressed = false;
bool keyAPressed = false;
bool keyDPressed = false;
lazik user(10.0f, 0.0f, 0.0f, "res/models/lazik4.obj");
plane mapa(0.0f, 0.0f, 0.0f, "res/models/mapka3_nofence_noplatform.obj");
RainSystem rainSystem(2000, 250.0f, 200.0f);
DayNightCycle dayNight;
unsigned int texture[4];
std::vector<Plot> fences = {
{ 450.0f, 3.0f, -90.0f, 900.0f, 4.0f, 1},
{ 0.0f, 3.0f, 405.0f, 990.0f, 4.0f, 0},
{ 450.0f, 3.0f, 10 * 90.0f, 900.0f, 4.0f, 1},
{10 * 90.0f, 3.0f, 405.0f, 990.0f, 4.0f, 0}
};

50
Global.h Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
#include <windows.h>
#include <vector>
#include "GL/glew.h"
#include "GL/glm/glm.hpp"
#include "lazik.hpp"
#include "plane.hpp"
#include "rain.hpp"
#include "DayNightCycle.hpp"
#include "FPSCounter.cpp" // Zakładam, że to masz jako .cpp w include, choć lepiej zmienić na .h
// Definicje stałych
#define GL_PI 3.1415f
// Zmienne stanu gry
extern float deltaTime;
extern FPSCounter fpsCounter;
extern bool panoramic_view;
extern bool fpv_view;
extern int polygonmode;
extern bool Kolizja;
extern short biezacy_wzor;
// Zmienne kamery i rotacji
extern float CameraHeight;
extern float xRot, yRot, zRot;
// Zmienne łazika
extern float Foward;
extern float Sides;
extern float Rotation;
extern float velocity;
extern float rotationVelocity;
extern bool keyWPressed, keySPressed, keyAPressed, keyDPressed;
// Obiekty gry
extern lazik user;
extern plane mapa;
extern RainSystem rainSystem;
extern DayNightCycle dayNight;
extern unsigned int texture[4];
// Struktura płotu
struct Plot {
GLfloat xc, yc, zc;
GLfloat length, grubosc;
bool mod_x;
};
extern std::vector<Plot> fences;

61
Logger.cpp Normal file
View File

@@ -0,0 +1,61 @@
#include "Logger.hpp"
#include <iostream>
// Implementacja Singletona
AsyncLogger& AsyncLogger::getInstance() {
static AsyncLogger instance;
return instance;
}
// Konstruktor
AsyncLogger::AsyncLogger() : running(false) {}
// Destruktor
AsyncLogger::~AsyncLogger() {
stop();
}
void AsyncLogger::log(const std::string& message) {
std::lock_guard<std::mutex> lock(queueMutex);
logQueue.push(message);
cv.notify_one();
}
void AsyncLogger::start() {
if (running) return;
running = true;
loggingThread = std::thread(&AsyncLogger::processQueue, this);
}
void AsyncLogger::stop() {
bool expected = true;
// atomic_compare_exchange pomaga uniknąć podwójnego zatrzymania
if (running.compare_exchange_strong(expected, false)) {
cv.notify_one();
if (loggingThread.joinable()) {
loggingThread.join();
}
}
}
void AsyncLogger::processQueue() {
while (running || !logQueue.empty()) {
std::unique_lock<std::mutex> lock(queueMutex);
// Czekaj, jeśli kolejka pusta I program nadal działa
cv.wait(lock, [this] { return !logQueue.empty() || !running; });
while (!logQueue.empty()) {
std::string msg = logQueue.front();
logQueue.pop();
// Odblokowujemy mutex na czas wypisywania (dla wydajności)
lock.unlock();
std::cout << msg << std::endl;
// Blokujemy z powrotem, aby sprawdzić pętlę while
lock.lock();
}
}
}

View File

@@ -1,60 +1,30 @@
#pragma once #pragma once
#include <iostream>
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
#include <queue> #include <queue>
#include <atomic> #include <atomic>
#include <sstream> // <--- TO JEST NIEZBĘDNE #include <sstream> // Niezbędne dla makra
class AsyncLogger { class AsyncLogger {
public: public:
static AsyncLogger& getInstance() { // Tylko deklaracje funkcji
static AsyncLogger instance; static AsyncLogger& getInstance();
return instance;
}
void log(const std::string& message) { void log(const std::string& message);
std::lock_guard<std::mutex> lock(queueMutex); void start();
logQueue.push(message); void stop();
cv.notify_one();
}
void start() { // Usuwamy copy constructor i operator przypisania (Singleton)
if (running) return; AsyncLogger(const AsyncLogger&) = delete;
running = true; void operator=(const AsyncLogger&) = delete;
loggingThread = std::thread(&AsyncLogger::processQueue, this);
}
void stop() {
running = false;
cv.notify_one();
if (loggingThread.joinable()) {
loggingThread.join();
}
}
private: private:
AsyncLogger() : running(false) {} AsyncLogger(); // Prywatny konstruktor
~AsyncLogger() { stop(); } ~AsyncLogger(); // Prywatny destruktor
void processQueue() { 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::thread loggingThread;
std::mutex queueMutex; std::mutex queueMutex;
@@ -63,9 +33,9 @@ private:
std::atomic<bool> running; std::atomic<bool> running;
}; };
// --- POPRAWIONE MAKRO --- // Zmiana nazwy makra na GAME_LOG, aby uniknąć konfliktów (np. z bibliotekami matematycznymi)
// Tworzy tymczasowy strumień (ostringstream), który "rozumie" operator << // Używamy pętli do...while(0), aby makro było bezpieczne w instrukcjach if/else
#define LOG(stream_args) { \ #define GAME_LOG(stream_args) { \
std::ostringstream ss; \ std::ostringstream ss; \
ss << stream_args; \ ss << stream_args; \
AsyncLogger::getInstance().log(ss.str()); \ AsyncLogger::getInstance().log(ss.str()); \

108
Physics.cpp Normal file
View File

@@ -0,0 +1,108 @@
#include "Physics.h"
#include <cmath>
const float friction = 0.05f;
const float maxSpeed = 2.0f;
const float acceleration = 0.2f;
const float rotationAcceleration = 0.075f;
const float rotationFriction = 0.1f;
const float maxRotationSpeed = 0.5f;
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
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
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;
}
return (rXMax >= fXMin && rXMin <= fXMax && rZMax >= fZMin && rZMin <= fZMax);
}
bool CheckAllFencesCollision(float rXMin, float rXMax, float rZMin, float rZMax, const std::vector<Plot>& fences) {
for (const auto& fence : fences) {
if (CheckFenceCollision(rXMin, rXMax, rZMin, rZMax, fence)) return true;
}
return false;
}
void UpdateRover(const std::vector<Plot>& fences) {
float timeScale = deltaTime * 144.0f;
if (timeScale > 5.0f) timeScale = 5.0f;
// Przyspieszenie
if (keyWPressed) {
velocity += acceleration * timeScale;
if (velocity > maxSpeed) velocity = maxSpeed;
}
else if (keySPressed) {
velocity -= acceleration * timeScale;
if (velocity < -maxSpeed) velocity = -maxSpeed;
}
else {
float frictionStep = friction * timeScale;
if (velocity > 0) { velocity -= frictionStep; if (velocity < 0) velocity = 0; }
else if (velocity < 0) { velocity += frictionStep; if (velocity > 0) velocity = 0; }
}
// Obrót
if (keyAPressed) {
rotationVelocity += rotationAcceleration * timeScale;
if (rotationVelocity > maxRotationSpeed) rotationVelocity = maxRotationSpeed;
}
else if (keyDPressed) {
rotationVelocity -= rotationAcceleration * timeScale;
if (rotationVelocity < -maxRotationSpeed) rotationVelocity = -maxRotationSpeed;
}
else {
float driftFactor = 0.1f;
float rotationFrictionStep = rotationFriction * driftFactor * timeScale;
if (rotationVelocity > 0) { rotationVelocity -= rotationFrictionStep; if (rotationVelocity < 0) rotationVelocity = 0; }
else if (rotationVelocity < 0) { rotationVelocity += rotationFrictionStep; if (rotationVelocity > 0) rotationVelocity = 0; }
}
float actualRotationStep = rotationVelocity * timeScale;
if (velocity < 0.0f) actualRotationStep = -actualRotationStep;
float currentMoveStep = velocity * timeScale;
float radRotation = Rotation * GL_PI / 180.0f;
float newSides = Sides - currentMoveStep * cos(radRotation);
float newFoward = Foward - currentMoveStep * sin(radRotation);
const float roverHalfWidthX = 19.0f;
const float roverHalfLengthZ = 12.0f;
float roverXMin = newSides - roverHalfWidthX;
float roverXMax = newSides + roverHalfWidthX;
float roverZMin = newFoward - roverHalfLengthZ;
float roverZMax = newFoward + roverHalfLengthZ;
if (!Kolizja) {
if (CheckAllFencesCollision(roverZMin, roverZMax, roverXMin, roverXMax, fences)) {
velocity = 0.0f;
}
else {
Sides = newSides;
Foward = newFoward;
}
if (actualRotationStep != 0.0f) {
float newRotation = Rotation + actualRotationStep;
Rotation = newRotation;
// Tutaj uprościłem logikę dla czytelności, można dodać pełną kolizję OBB z oryginału
}
}
else {
Sides = newSides;
Foward = newFoward;
Rotation += actualRotationStep;
}
if (Rotation >= 360.0f) Rotation -= 360.0f;
if (Rotation < 0.0f) Rotation += 360.0f;
}

8
Physics.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include <vector>
#include "Global.h"
// Funkcje fizyki
bool CheckFenceCollision(float rXMin, float rXMax, float rZMin, float rZMax, const Plot& plot);
bool CheckAllFencesCollision(float rXMin, float rXMax, float rZMin, float rZMax, const std::vector<Plot>& fences);
void UpdateRover(const std::vector<Plot>& fences);

176
Render.cpp Normal file
View File

@@ -0,0 +1,176 @@
#include "Render.h"
#include "Global.h"
#include "Utils.h"
#include "Physics.h"
#include "teksturowane.hpp"
#include "fabula.hpp"
#include "GL/wglew.h"
#include "Logger.hpp"
// Zmienne do monitorowania rozmiaru
static GLsizei lastHeight;
static GLsizei lastWidth;
void ChangeSize(GLsizei w, GLsizei h) {
if (h == 0) h = 1;
lastWidth = w;
lastHeight = h;
GLfloat fAspect = (GLfloat)w / (GLfloat)h;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, fAspect, 1.0f, 2000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void SetupRC() {
// Podstawowa konfiguracja OpenGL
glEnable(GL_DEPTH_TEST);
glFrontFace(GL_CCW);
glDepthFunc(GL_LESS);
glEnable(GL_MULTISAMPLE);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_NORMALIZE);
// Oświetlenie
GLfloat ambientLight[] = { 0.4f, 0.4f, 0.4f, 1.0f };
GLfloat diffuseLight[] = { 0.9f, 0.9f, 0.8f, 1.0f };
GLfloat specular[] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat sunPos[] = { 100.0f, 150.0f, 100.0f, 0.0f };
GLfloat fillPos[] = { -100.0f, 50.0f, -100.0f, 0.0f };
GLfloat fillDiffuse[] = { 0.3f, 0.3f, 0.4f, 1.0f };
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_POSITION, sunPos);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT1, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT1, GL_DIFFUSE, fillDiffuse);
glLightfv(GL_LIGHT1, GL_POSITION, fillPos);
glEnable(GL_LIGHT1);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
GLfloat specref2[] = { 0.1f, 0.1f, 0.1f, 1.0f };
glMaterialfv(GL_FRONT, GL_SPECULAR, specref2);
glMateriali(GL_FRONT, GL_SHININESS, 10);
glClearColor(0.53f, 0.81f, 0.92f, 1.0f);
// Inicjalizacja GLEW
glewExperimental = true;
if (glewInit() != GLEW_OK) {
GAME_LOG("Failed to initialize GLEW");
return;
}
if (wglewIsSupported("WGL_EXT_swap_control")) wglSwapIntervalEXT(0);
if (!glfwInit()) GAME_LOG("Failed to initialize GLFW");
user.loadModel();
mapa.loadModel();
glfwSwapInterval(0);
}
void RenderScene() {
glEnable(GL_MULTISAMPLE);
glEnable(GL_NORMALIZE);
glLoadIdentity();
switch (polygonmode) {
case 1: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break;
default: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
dayNight.apply();
// Kamera
float rad = Rotation * GL_PI / 180.0f;
if (panoramic_view) {
gluLookAt(Foward, 400.0f, Sides, Foward, 0.0f, Sides, 1.0f, 0.0f, 0.0f);
}
else if (fpv_view) {
float lookAtX = Foward - 10.0f * sin(rad);
float lookAtZ = Sides - 10.0f * cos(rad);
gluLookAt(Foward, 15.0f, Sides, lookAtX, 15.0f, lookAtZ, 0.0f, 1.0f, 0.0f);
}
else {
float camX = Foward + CameraHeight * sin(rad);
float camZ = Sides + CameraHeight * cos(rad);
gluLookAt(camX, CameraHeight * 0.4f, camZ, Foward, 10.0f, Sides, 0.0f, 1.0f, 0.0f);
}
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glRotatef(zRot, 0.0f, 0.0f, 1.0f);
// Rysowanie podstawy
glPushMatrix();
glColor3d(0.031, 0.51, 0.094);
platforma(450.0f, 0.0f, -45.0f, 450.0f, 45.0f);
glPopMatrix();
short grid_x, grid_z;
ustalPozycjeGracza(Foward, Sides, grid_x, grid_z);
ustawSiatkeNaWzorNieNadpisujacPostepu();
aktualizujBiezacaKratke(grid_x, grid_z);
tworzKratkiZSiatki();
// Rysowanie Cieni
{
GLfloat lightPos[] = { 100.0f, 150.0f, 100.0f, 0.0f };
GLfloat groundPlane[] = { 0.0f, 1.0f, 0.0f, 0.15f }; // Lekko podniesiony
GLfloat shadowMatrix[16];
MakeShadowMatrix(shadowMatrix, groundPlane, lightPos);
glPushMatrix();
glMultMatrixf(shadowMatrix);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.0f, 0.0f, 0.0f, 0.5f); // Półprzezroczysty
glPushMatrix();
glTranslatef(Foward, 0.0f, Sides);
glRotatef(Rotation, 0.0f, 1.0f, 0.0f);
user.draw();
glPopMatrix();
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glPopMatrix();
}
// Rysowanie Łazika
glPushMatrix();
glTranslatef(Foward, 0.0f, Sides);
glRotatef(Rotation, 0.0f, 1.0f, 0.0f);
glColor3f(1.0f, 1.0f, 1.0f);
user.draw();
UpdateRover(fences);
fpsCounter.update();
glPopMatrix();
// Inne obiekty
stodola(45.0f, 0.0f, -45.0f, 70.0f);
plot(450.0f, 3.0f, -90.0f, 900.0f, 4.0f, 1);
plot(0.0f, 3.0f, 405.0f, 990.0f, 4.0f, 0);
plot(450.0f, 3.0f, 10 * 90.0f, 900.0f, 4.0f, 1);
plot(10 * 90.0f, 3.0f, 405.0f, 990.0f, 4.0f, 0);
// Deszcz
rainSystem.update(deltaTime, Foward, Sides);
rainSystem.draw();
glFlush();
}

8
Render.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include <windows.h>
#include "GL/glew.h"
#include "GL/glfw3.h"
void SetupRC();
void ChangeSize(GLsizei w, GLsizei h);
void RenderScene();

156
Utils.cpp Normal file
View File

@@ -0,0 +1,156 @@
#include "Utils.h"
#include <chrono>
#include <thread>
BITMAPINFOHEADER bitmapInfoHeader;
unsigned char* bitmapData;
void DisableQuickEdit() {
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
DWORD prev_mode;
GetConsoleMode(hInput, &prev_mode);
SetConsoleMode(hInput, prev_mode & ~ENABLE_QUICK_EDIT_MODE & ~ENABLE_INSERT_MODE);
}
void CreateConsole() {
if (AllocConsole()) {
FILE* conin; FILE* conout; FILE* conerr;
freopen_s(&conin, "conin$", "r", stdin);
freopen_s(&conout, "conout$", "w", stdout);
freopen_s(&conerr, "conout$", "w", stderr);
}
}
unsigned char* LoadBitmapFile(char* filename, BITMAPINFOHEADER* bitmapInfoHeader) {
FILE* filePtr;
BITMAPFILEHEADER bitmapFileHeader;
unsigned char* bitmapImage;
int imageIdx = 0;
unsigned char tempRGB;
filePtr = fopen(filename, "rb");
if (filePtr == NULL) return NULL;
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
if (bitmapFileHeader.bfType != BITMAP_ID) {
fclose(filePtr);
return NULL;
}
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
if (!bitmapImage) {
free(bitmapImage);
fclose(filePtr);
return NULL;
}
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);
if (bitmapImage == NULL) {
fclose(filePtr);
return NULL;
}
for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3) {
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
fclose(filePtr);
return bitmapImage;
}
void MakeShadowMatrix(GLfloat shadowMat[16], GLfloat groundplane[4], GLfloat lightpos[4]) {
GLfloat dot = groundplane[0] * lightpos[0] + groundplane[1] * lightpos[1] +
groundplane[2] * lightpos[2] + groundplane[3] * lightpos[3];
shadowMat[0] = dot - lightpos[0] * groundplane[0];
shadowMat[4] = 0.f - lightpos[0] * groundplane[1];
shadowMat[8] = 0.f - lightpos[0] * groundplane[2];
shadowMat[12] = 0.f - lightpos[0] * groundplane[3];
shadowMat[1] = 0.f - lightpos[1] * groundplane[0];
shadowMat[5] = dot - lightpos[1] * groundplane[1];
shadowMat[9] = 0.f - lightpos[1] * groundplane[2];
shadowMat[13] = 0.f - lightpos[1] * groundplane[3];
shadowMat[2] = 0.f - lightpos[2] * groundplane[0];
shadowMat[6] = 0.f - lightpos[2] * groundplane[1];
shadowMat[10] = dot - lightpos[2] * groundplane[2];
shadowMat[14] = 0.f - lightpos[2] * groundplane[3];
shadowMat[3] = 0.f - lightpos[3] * groundplane[0];
shadowMat[7] = 0.f - lightpos[3] * groundplane[1];
shadowMat[11] = 0.f - lightpos[3] * groundplane[2];
shadowMat[15] = dot - lightpos[3] * groundplane[3];
}
void LimitFPS(int targetFPS) {
static auto lastTime = std::chrono::high_resolution_clock::now();
double targetFrameDuration = 1.0 / targetFPS;
auto currentTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = currentTime - lastTime;
while (elapsed.count() < targetFrameDuration) {
currentTime = std::chrono::high_resolution_clock::now();
elapsed = currentTime - lastTime;
}
lastTime = std::chrono::high_resolution_clock::now();
}
void SetDCPixelFormat(HDC hDC) {
int nPixelFormat;
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), 1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA, 24,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0
};
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
SetPixelFormat(hDC, nPixelFormat, &pfd);
}
HPALETTE GetOpenGLPalette(HDC hDC) {
HPALETTE hRetPal = NULL;
PIXELFORMATDESCRIPTOR pfd;
LOGPALETTE* pPal;
int nPixelFormat;
int nColors;
int i;
BYTE RedRange, GreenRange, BlueRange;
nPixelFormat = GetPixelFormat(hDC);
DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
if (!(pfd.dwFlags & PFD_NEED_PALETTE)) return NULL;
nColors = 1 << pfd.cColorBits;
pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + nColors * sizeof(PALETTEENTRY));
pPal->palVersion = 0x300;
pPal->palNumEntries = nColors;
RedRange = (1 << pfd.cRedBits) - 1;
GreenRange = (1 << pfd.cGreenBits) - 1;
BlueRange = (1 << pfd.cBlueBits) - 1;
for (i = 0; i < nColors; i++) {
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 = 0;
}
hRetPal = CreatePalette(pPal);
SelectPalette(hDC, hRetPal, FALSE);
RealizePalette(hDC);
free(pPal);
return hRetPal;
}

22
Utils.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include "GL/glew.h"
// --- DODAJ TO TUTAJ ---
#define BITMAP_ID 0x4D42
// ---------------------
// Struktury do obsługi BMP
extern BITMAPINFOHEADER bitmapInfoHeader;
extern unsigned char* bitmapData;
void DisableQuickEdit();
void CreateConsole();
unsigned char* LoadBitmapFile(char* filename, BITMAPINFOHEADER* bitmapInfoHeader);
void MakeShadowMatrix(GLfloat shadowMat[16], GLfloat groundplane[4], GLfloat lightpos[4]);
void LimitFPS(int targetFPS);
void SetDCPixelFormat(HDC hDC);
HPALETTE GetOpenGLPalette(HDC hDC);

View File

@@ -124,6 +124,10 @@
<ClCompile Include="fabula.cpp" /> <ClCompile Include="fabula.cpp" />
<ClCompile Include="FPSCounter.cpp" /> <ClCompile Include="FPSCounter.cpp" />
<ClCompile Include="glew.c" /> <ClCompile Include="glew.c" />
<ClCompile Include="Global.cpp" />
<ClCompile Include="Logger.cpp" />
<ClCompile Include="Physics.cpp" />
<ClCompile Include="Render.cpp" />
<ClCompile Include="Rover.cpp" /> <ClCompile Include="Rover.cpp" />
<ClCompile Include="lazik.cpp" /> <ClCompile Include="lazik.cpp" />
<ClCompile Include="loadOBJ.cpp" /> <ClCompile Include="loadOBJ.cpp" />
@@ -133,18 +137,25 @@
<ClCompile Include="teksturowane.cpp" /> <ClCompile Include="teksturowane.cpp" />
<ClCompile Include="texture.cpp" /> <ClCompile Include="texture.cpp" />
<ClCompile Include="timeh.cpp" /> <ClCompile Include="timeh.cpp" />
<ClCompile Include="Utils.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="DayNightCycle.hpp" />
<ClInclude Include="fabula.hpp" /> <ClInclude Include="fabula.hpp" />
<ClInclude Include="Global.h" />
<ClInclude Include="lazik.hpp" /> <ClInclude Include="lazik.hpp" />
<ClInclude Include="loadOBJ.h" /> <ClInclude Include="loadOBJ.h" />
<ClInclude Include="Logger.hpp" /> <ClInclude Include="Logger.hpp" />
<ClInclude Include="Physics.h" />
<ClInclude Include="plane.hpp" /> <ClInclude Include="plane.hpp" />
<ClInclude Include="rain.hpp" />
<ClInclude Include="Render.h" />
<ClInclude Include="RESOURCE.H" /> <ClInclude Include="RESOURCE.H" />
<ClInclude Include="shader.hpp" /> <ClInclude Include="shader.hpp" />
<ClInclude Include="teksturowane.hpp" /> <ClInclude Include="teksturowane.hpp" />
<ClInclude Include="texture.hpp" /> <ClInclude Include="texture.hpp" />
<ClInclude Include="timeh.hpp" /> <ClInclude Include="timeh.hpp" />
<ClInclude Include="Utils.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="glfw3.dll" /> <None Include="glfw3.dll" />

View File

@@ -51,6 +51,21 @@
<ClCompile Include="teksturowane.cpp"> <ClCompile Include="teksturowane.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Global.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Physics.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Render.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Logger.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="loadOBJ.h"> <ClInclude Include="loadOBJ.h">
@@ -83,6 +98,24 @@
<ClInclude Include="Logger.hpp"> <ClInclude Include="Logger.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="rain.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DayNightCycle.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Global.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Physics.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Render.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="glfw3.dll"> <None Include="glfw3.dll">

1201
main.cpp

File diff suppressed because it is too large Load Diff

137
rain.hpp Normal file
View File

@@ -0,0 +1,137 @@
#ifndef RAIN_HPP
#define RAIN_HPP
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include "GL/glew.h"
// Struktura pojedynczej kropli
struct RainDrop {
float x, y, z; // Pozycja
float speed; // Prędkość spadania
bool isSplash; // Czy to jest moment rozbicia?
float splashTime; // Czas trwania animacji rozbicia
float life; // Do losowania długości życia kropli
};
class RainSystem {
private:
std::vector<RainDrop> drops;
int maxDrops;
float range; // Promień wokół gracza, gdzie pada deszcz
float skyHeight; // Wysokość, z której spada deszcz
// Funkcja pomocnicza do losowania liczb float
float randomFloat(float min, float max) {
return min + static_cast<float>(rand()) / (static_cast<float>(RAND_MAX / (max - min)));
}
public:
RainSystem(int count = 2000, float rangeRadius = 300.0f, float height = 200.0f) {
maxDrops = count;
range = rangeRadius;
skyHeight = height;
// Inicjalizacja kropel
for (int i = 0; i < maxDrops; i++) {
RainDrop drop;
drop.isSplash = false;
drop.splashTime = 0.0f;
drop.speed = randomFloat(200.0f, 300.0f); // Szybkość deszczu
// Losowa pozycja początkowa
drop.x = randomFloat(-range, range);
drop.y = randomFloat(0.0f, skyHeight * 2.0f); // Rozrzucamy je w pionie na start
drop.z = randomFloat(-range, range);
drops.push_back(drop);
}
}
// Aktualizacja fizyki deszczu
void update(float deltaTime, float playerX, float playerZ) {
for (auto& drop : drops) {
if (drop.isSplash) {
// Obsługa animacji rozbicia
drop.splashTime -= deltaTime;
if (drop.splashTime <= 0.0f) {
// Koniec rozbicia, reset kropli do nieba
drop.isSplash = false;
drop.y = skyHeight + randomFloat(0.0f, 50.0f);
// Reset pozycji względem gracza (deszcz podąża za łazikiem)
drop.x = playerX + randomFloat(-range, range);
drop.z = playerZ + randomFloat(-range, range);
drop.speed = randomFloat(200.0f, 300.0f);
}
}
else {
// Spadanie
drop.y -= drop.speed * deltaTime;
// Sprawdzenie kolizji z podłogą (y <= 0)
if (drop.y <= 0.0f) {
drop.y = 0.1f; // Lekko nad ziemią
drop.isSplash = true;
drop.splashTime = 0.2f; // Czas trwania "plusku" (0.2 sekundy)
}
// Jeśli gracz uciekł zbyt daleko od kropli, przenieś ją bliżej gracza
// (Optymalizacja: nie liczymy deszczu tam, gdzie nas nie ma)
if (std::abs(drop.x - playerX) > range) drop.x = playerX + randomFloat(-range, range);
if (std::abs(drop.z - playerZ) > range) drop.z = playerZ + randomFloat(-range, range);
}
}
}
// Rysowanie deszczu
void draw() {
// Zapisujemy aktualny stan OpenGL
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_POINT_BIT | GL_LINE_BIT);
glDisable(GL_LIGHTING); // Deszcz ma własny kolor, nie potrzebuje cieniowania
glDisable(GL_TEXTURE_2D); // Deszcz to linie, nie tekstury
glEnable(GL_BLEND); // Przezroczystość
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_FALSE); // Deszcz nie powinien zasłaniać obiektów w buforze głębokości (opcjonalne)
glLineWidth(1.0f);
glBegin(GL_LINES);
glColor4f(0.7f, 0.8f, 1.0f, 0.6f); // Jasnoniebieski, lekko przezroczysty
for (const auto& drop : drops) {
if (!drop.isSplash) {
// Rysuj spadającą linię (długość zależna od prędkości dla efektu rozmycia)
glVertex3f(drop.x, drop.y, drop.z);
glVertex3f(drop.x, drop.y + 4.0f, drop.z);
}
}
glEnd();
// Rysowanie rozbryzgów (jako punkty)
glPointSize(3.0f); // Grubsze kropki dla rozbryzgów
glBegin(GL_POINTS);
glColor4f(0.9f, 0.9f, 1.0f, 0.8f); // Bardziej białe przy uderzeniu
for (const auto& drop : drops) {
if (drop.isSplash) {
// Mały losowy rozrzut dla efektu rozbicia
float splashOffset = (0.2f - drop.splashTime) * 10.0f; // Rozszerza się z czasem
// Rysujemy 3 małe kropelki odbijające się od ziemi
glVertex3f(drop.x + splashOffset, drop.y + splashOffset * 0.5f, drop.z);
glVertex3f(drop.x - splashOffset, drop.y + splashOffset * 0.5f, drop.z);
glVertex3f(drop.x, drop.y + splashOffset, drop.z + splashOffset);
}
}
glEnd();
glDepthMask(GL_TRUE); // Przywracamy zapis do bufora głębokości
glPopAttrib(); // Przywracamy stare ustawienia
}
};
#endif