From 079ab7933d28177b9be9a37b25b33cc2cc84b7bd Mon Sep 17 00:00:00 2001 From: MackValentine Date: Thu, 17 Oct 2024 18:42:23 +0200 Subject: [PATCH] DoomView - WIP Add Walls --- src/game_interpreter.cpp | 11 ++ src/game_interpreter.h | 1 + src/game_pictures.cpp | 14 ++ src/game_pictures.h | 2 + src/spritesetmap_doom.cpp | 384 ++++++++++++++++++++++++++++++++++---- src/spritesetmap_doom.h | 32 ++++ 6 files changed, 405 insertions(+), 39 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 8765ae4f72..2a2cbf2a21 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -826,6 +826,8 @@ bool Game_Interpreter::ExecuteCommand(lcf::rpg::EventCommand const& com) { return CommandManiacControlStrings(com); case Cmd::Maniac_CallCommand: return CommandManiacCallCommand(com); + case 9900: + return CommandSetDoomMap(com); case 9901: return Command3DPicture(com); case 9902: @@ -5209,3 +5211,12 @@ bool Game_Interpreter::CommandGet3DPictureRotate(lcf::rpg::EventCommand const& c return true; } +bool Game_Interpreter::CommandSetDoomMap(lcf::rpg::EventCommand const& com) { + + int picID = ValueOrVariable(com.parameters[0], com.parameters[1]); + + Main_Data::game_pictures->ShowDoomMap(picID); + + return true; +} + diff --git a/src/game_interpreter.h b/src/game_interpreter.h index c19a986ac7..914c4a4324 100644 --- a/src/game_interpreter.h +++ b/src/game_interpreter.h @@ -292,6 +292,7 @@ class Game_Interpreter bool Command3DPicture(lcf::rpg::EventCommand const& com); bool Command3DPictureRotate(lcf::rpg::EventCommand const& com); bool CommandGet3DPictureRotate(lcf::rpg::EventCommand const& com); + bool CommandSetDoomMap(lcf::rpg::EventCommand const& com); int DecodeInt(lcf::DBArray::const_iterator& it); const std::string DecodeString(lcf::DBArray::const_iterator& it); diff --git a/src/game_pictures.cpp b/src/game_pictures.cpp index 93b47d63c3..c57ac2f3d8 100644 --- a/src/game_pictures.cpp +++ b/src/game_pictures.cpp @@ -676,6 +676,10 @@ void Game_Pictures::Get3DRotation(int picID, int vx, int vy, int vz) { auto& pic = GetPicture(picID); pic.Get3DRotation(vx, vy, vz); } +void Game_Pictures::ShowDoomMap(int picID) { + auto& pic = GetPicture(picID); + pic.ShowDoomMap(); +} void Game_Pictures::Picture::Show3D(std::string n, int zoom, int dx, int dy, int rx, int ry, int rz) { pic3D = new Spriteset_MapDoom(n, zoom, dx, dy, rx, ry, rz); @@ -698,4 +702,14 @@ void Game_Pictures::Picture::Get3DRotation(int vx, int vy, int vz) { } } +void Game_Pictures::Picture::ShowDoomMap() { + pic3D = new Spriteset_MapDoom(); + + if (!sprite) { + CreateSprite(); + needs_update = true; + } + +} + diff --git a/src/game_pictures.h b/src/game_pictures.h index af4483e885..12be364a17 100644 --- a/src/game_pictures.h +++ b/src/game_pictures.h @@ -88,6 +88,7 @@ class Game_Pictures { void Show3D(std::string n, int picID, int zoom, int dx, int dy, int rx, int ry, int rz); void Rotate3D(int picID, int rx, int ry, int rz); void Get3DRotation(int picID, int vx, int vy, int vz); + void ShowDoomMap(int picID); void Erase(int id); void EraseAll(); @@ -136,6 +137,7 @@ class Game_Pictures { void Show3D(std::string n, int zoom, int dx, int dy, int rx, int ry, int rz); void Rotate3D(int rx, int ry, int rz); void Get3DRotation(int vx, int vy, int vz); + void ShowDoomMap(); Spriteset_MapDoom* pic3D = nullptr; }; diff --git a/src/spritesetmap_doom.cpp b/src/spritesetmap_doom.cpp index 206e108fb3..d4c1440613 100644 --- a/src/spritesetmap_doom.cpp +++ b/src/spritesetmap_doom.cpp @@ -6,59 +6,306 @@ #include #include #include +#include +#include +#include +#include "game_map.h" +#include "game_player.h" +#include + +int Spriteset_MapDoom::mapWidth() { + return mapW; +} +int Spriteset_MapDoom::mapHeight() { + return mapH; +} +float Spriteset_MapDoom::castRay(float rayAngle, int &ray) { + + float rayPosX = player.x; + float rayPosY = player.y; + + // Direction du rayon + float rayDirX = cos(rayAngle); + float rayDirY = sin(rayAngle); + + int mapX = (int)(rayPosX / TILE_SIZE); + int mapY = (int)(rayPosY / TILE_SIZE); + + float rayDistance = 0.0; + bool hit = false; + + while (!hit) { + // Vérification si le rayon sort des limites de la carte + if (mapX < 0 || mapX >= mapWidth() || mapY < 0 || mapY >= mapHeight()) { + break; // Sortir de la boucle si on dépasse la carte + } + + // Vérifier si le rayon touche un mur + if (map[mapY][mapX] == 1) { + hit = true; + } + else { + // Incrémenter la position du rayon + rayPosX += rayDirX; + rayPosY += rayDirY; + + mapX = (int)(rayPosX / TILE_SIZE); + mapY = (int)(rayPosY / TILE_SIZE); + + // Calcul de la distance actuelle du rayon + rayDistance += sqrt(rayDirX * rayDirX + rayDirY * rayDirY); + } + } + + ray = (int) rayPosX % TILE_SIZE; + if (ray == 0 || ray == TILE_SIZE - 1) + ray = (int)rayPosY % TILE_SIZE; + + return rayDistance; // Retourner la distance si un mur est touché +} + + +// Fonction pour dessiner la scène en utilisant les fonctions de Spriteset_MapDoom +void Spriteset_MapDoom::renderScene() { + + + //renderTexturedFloor(player.x, player.y, player.angle); + + + for (int x = 0; x < Player::screen_width; x++) { + // Calculer l'angle du rayon + float rayAngle = player.angle + atan2(x - Player::screen_width / 2, Player::screen_width / 2); + + + int ray = 0; + + // Cast le rayon et obtenir la distance + float distance = castRay(rayAngle, ray); + + // Si la distance est valide, dessinez les murs + if (distance > 0) { + int lineHeight = static_cast(TILE_SIZE * Player::screen_height / distance); + int drawStart = (Player::screen_height - lineHeight) / 2; + int drawEnd = drawStart + lineHeight; + + // Calculer la position de la texture + int textureX = static_cast((distance / TILE_SIZE) * TILE_SIZE) % TILE_SIZE; // Choisir la colonne de texture + + textureX = ray; + + Rect r = Rect(x, drawStart, 1, drawEnd - drawStart); + BitmapRef texture = mapTexture(1, 0); + + if (texture) { + Rect srcRect = { textureX, 0, 1, texture->height() }; + sprite->StretchBlit(r, *texture, srcRect, 255); + } + //drawTexture(image, x, drawStart, 1, drawEnd - drawStart, wallTexture, textureX, 0); + } + } + + return; + + //for (int x = 0; x < Player::screen_width; x++) { + + // float rayAngle = player.angle + atan2(x - Player::screen_width / 2, Player::screen_width / 2); + + // int ray = 0; + // // Lancer le rayon et calculer la distance entre le joueur et le mur touché + // float rayDistance = castRay(rayAngle, ray); + + // // Correction du fish-eye effect + // rayDistance = rayDistance * cos(rayAngle - player.angle); + + // // Calculer la hauteur de la ligne du mur (projetée correctement) + // int lineHeight = (int)(TILE_SIZE * Player::screen_height / rayDistance); + + + // int drawStart = -lineHeight / 2 + Player::screen_height / 2; + // if (drawStart < 0) drawStart = 0; + // int drawEnd = lineHeight / 2 + Player::screen_height / 2; + // if (drawEnd >= Player::screen_height) drawEnd = Player::screen_height - 1; + + // float darknessFactor = 1.0f / (1.0f + rayDistance * 0.05f); + + // Color baseColor = Color(255, 0, 0, 255); + + // // Appliquer le facteur d'assombrissement sur les composantes RGB + // int red = (int)(baseColor.red * darknessFactor); + // int green = (int)(baseColor.green * darknessFactor); + // int blue = (int)(baseColor.blue * darknessFactor); + + // // S'assurer que les valeurs de couleur restent dans les limites valides [0, 255] + // red = std::min(255, std::max(0, red)); + // green = std::min(255, std::max(0, green)); + // blue = std::min(255, std::max(0, blue)); + + // Color color = Color(red, green, blue, 255); + + // int h = drawEnd - drawStart; + // if (h < 0) + // h *= -1; + + // Rect r = Rect(x, drawStart, 1, h); + + // sprite->FillRect(r, color); + + // BitmapRef texture = mapTexture(1, 0); + + // if (texture) { + + // Rect srcRect = { 0, 0, 1, texture->height() }; + + // // Appliquer les textures + // r.height /= 2; + // sprite->StretchBlit(r, *texture, srcRect, 255); + // r.y += r.height; + // sprite->StretchBlit(r, *texture, srcRect, 255); + + // //int textureWidth = texture->width(); + // ////float wallX = fmod(rayDistance, TILE_SIZE) / TILE_SIZE; // Position horizontale dans la texture + // //float wallX = x % TILE_SIZE / (float)TILE_SIZE; + // //int textureX = (int)(wallX * textureWidth); + // //Rect srcRect = { textureX, 0, 1, texture->height() }; + + // ////sprite->BlitScale(r, *texture, srcRect); + // //r.height /= 2; + // //sprite->StretchBlit(r, *texture, srcRect, 255); + // //r.y += r.height; + // //sprite->StretchBlit(r, *texture, srcRect, 255); + // } -Spriteset_MapDoom::Spriteset_MapDoom() { - //renderer = SDL_GetRenderer(SDL_GetGrabbedWindow()); - //for (int i = 0;i<100; i++) { - // pixel(i,i); //} +} - //line(0, 0, 64, 0); +void Spriteset_MapDoom::renderFloorAndCeiling(float playerX, float playerY, float playerAngle) { - // Cube - points3D = { {100,100,-50}, {200,100,-50}, {200,200,-50}, {100,200,-50}, - {100,100,50}, {200,100,50}, {200,200,50}, {100,200,50} }; +} - connections3D = { {0,4}, {1,5}, {2,6}, {3,7}, - {0,1}, {1,2}, {2,3}, {3,0}, - {4,5}, {5,6},{6,7}, {7,4} }; - // +BitmapRef Spriteset_MapDoom::mapTexture(int x, int y) { + if (x==0) + return bitmap; + return bitmap2; +} - centeroid = { 0,0,0 }; - for (auto& p : points3D) { - centeroid.x += p.x; - centeroid.y += p.y; - centeroid.z += p.z; +void Spriteset_MapDoom::renderTexturedFloor(float playerX, float playerY, float playerAngle) { + + + for (int x = 0; x < Player::screen_width; x++) { + // Calculer l'angle du rayon + float rayAngle = player.angle + atan2(x - Player::screen_width / 2, Player::screen_width / 2); + + int ray = 0; + + // Cast le rayon et obtenir la distance au mur + float distance = castRay(rayAngle, ray); + + // Si la distance est valide + if (distance > 0) { + float floorDistance = (Player::screen_height / 2) / tan(player.fov / 2); + + // On utilise rayDistance pour déterminer la distance du sol + float actualFloorDistance = distance * cos(rayAngle - player.angle); // Correction avec l'angle du rayon + + // Calculer la position de la texture sur le sol + float floorX = player.x + actualFloorDistance * cos(rayAngle); + float floorY = player.y + actualFloorDistance * sin(rayAngle); + + // Pour récupérer la position de la texture correcte + // Utiliser la position du joueur pour calculer textureX + int mapX = static_cast(floorX / TILE_SIZE); + int mapY = static_cast(floorY / TILE_SIZE); + float wallX = fmod(floorX, TILE_SIZE); // Position horizontale dans la tuile + + + // Dessiner le sol en utilisant la texture + for (int y = Player::screen_height / 2; y < Player::screen_height; y++) { + + //drawTexture(image, x, y, 1, 1, floorTexture, textureX, textureY); + + + Rect r = Rect(x, y, 1, 1); + BitmapRef texture = mapTexture(0, 0); + + if (texture) { + + int textureWidth = texture->width(); + + // Calculer textureX + int textureX = static_cast((wallX / TILE_SIZE) * textureWidth); + int textureY = static_cast(((y - Player::screen_height / 2) / (Player::screen_height / 2)) * texture->height()); + + // Assurez-vous que textureY est dans les limites de la texture + textureY = std::min(textureY, texture->height() - 1); + + Rect srcRect = { textureX, textureY, 1, 1 }; + sprite->StretchBlit(r, *texture, srcRect, 255); + } + } + } } - centeroid.x /= points3D.size(); - centeroid.y /= points3D.size(); - centeroid.z /= points3D.size(); - for (auto& p : points3D) { - p.x -= centeroid.x; - p.y -= centeroid.y; - p.z -= centeroid.z; - //rotate(p, 0.08, 0, 0); - p.x += centeroid.x; - p.y += centeroid.y; - p.z += centeroid.z; +} + + +Spriteset_MapDoom::Spriteset_MapDoom() { + + + doomMap = true; + + mapW = Game_Map::GetTilesX(); + mapH = Game_Map::GetTilesY(); + + Output::Debug("Map size {} {}", mapWidth(), mapHeight()); + + auto m = Game_Map::GetPassagesDown(); + + for (int x = 0;x < mapWidth(); x++) { + for (int y = 0; y < mapHeight(); y++) { + map[y][x] = Game_Map::GetTerrainTag(x, y) - 1; + } } - sprite = Bitmap::Create(480, 256); - spriteUpper = Bitmap::Create(480, 256); + player.x = Main_Data::game_player->GetX() * TILE_SIZE; + player.y = Main_Data::game_player->GetY() * TILE_SIZE; + + sprite = Bitmap::Create(Player::screen_width, Player::screen_height); + spriteUpper = Bitmap::Create(Player::screen_width, Player::screen_height); + + tilemap = std::make_unique(); + tilemap->SetWidth(Game_Map::GetTilesX()); + tilemap->SetHeight(Game_Map::GetTilesY()); + + FileRequestAsync* request = AsyncHandler::RequestFile("Pictures", "floor"); + request->SetGraphicFile(true); + request_id = request->Bind(&Spriteset_MapDoom::OnTitleSpriteReady, this, 0); + request->Start(); + + + request = AsyncHandler::RequestFile("Pictures", "wall"); + request->SetGraphicFile(true); + request_id = request->Bind(&Spriteset_MapDoom::OnTitleSpriteReady, this, 1); + request->Start(); + +} + +void Spriteset_MapDoom::OnTitleSpriteReady(FileRequestResult* result, int i) { + BitmapRef bitmapRef = Cache::Picture(result->file, false); + + if (i == 0) + bitmap = bitmapRef; + else + bitmap2 = bitmapRef; + + Update(true); } Spriteset_MapDoom::Spriteset_MapDoom(std::string n, int zoom, int dx, int dy, int rx, int ry, int rz) { Load_OBJ(n); - //points3D = {}; - //connections3D = {}; - //surfaces = { { {16,16}, {16,24},{32,32},{16,16} ,{48,24} }}; - //surfaces = { {{41,5} ,{31,82}, {37,82}}, {{41,5} ,{31,82},{46,82}}, {{27,83}, {48,83}, {27,92}, {48,92}} }; - displayX = dx; displayY = dy; rotationX = rx; @@ -315,6 +562,54 @@ void Spriteset_MapDoom::Update(bool first) { int refresh_rate = 2; + if (doomMap) { + int s = 1; + float angle = 0.02; + + if (Input::IsPressed(Input::UP)) { // Avancer + float px = player.x + cos(player.angle) * s * 16; + float py = player.y + sin(player.angle) * s * 16; + + int ppx = px / TILE_SIZE; + int ppy = py / TILE_SIZE; + + Output::Debug(" {} {} {}", ppx, ppy, map[ppx][ppy]); + + if (ppx < mapWidth() && ppy < mapHeight() && ppx >= 0 && ppy >= 0) + if (map[ppy][ppx] == 0) { + player.x = player.x + cos(player.angle) * s; + player.y = player.y + sin(player.angle) * s; + } + } + if (Input::IsPressed(Input::DOWN)) { // Reculer + float px = player.x - cos(player.angle) * s; + float py = player.y - sin(player.angle) * s; + + int ppx = px / TILE_SIZE; + int ppy = py / TILE_SIZE; + + Output::Debug(" {} {} {}", ppx, ppy, map[ppx][ppy]); + + if (ppx < mapWidth() && ppy < mapHeight() && ppx >= 0 && ppy >= 0) + if (map[ppy][ppx] == 0) { + player.x = px; + player.y = py; + } + } + if (Input::IsPressed(Input::LEFT)) { // Tourner à gauche + player.angle -= angle; + } + if (Input::IsPressed(Input::RIGHT)) { // Tourner à droite + player.angle += angle; + } + + sprite->Clear(); + renderScene(); + points.clear(); + + return; + } + if (rotationX != 0 || rotationY != 0 || rotationZ != 0 || first) { @@ -331,7 +626,10 @@ void Spriteset_MapDoom::Update(bool first) { p.x -= centeroid.x; p.y -= centeroid.y; p.z -= centeroid.z; - rotate(p, rotationX / 1000.0, rotationY / 1000.0, rotationZ / 1000.0); + // rotate(p, rotationX / 1000.0, rotationY / 1000.0, rotationZ / 1000.0); + rotate(p, rotationX / 1000.0, 0, 0); + rotate(p, 0, rotationY / 1000.0, 0); + rotate(p, 0, 0, rotationZ / 1000.0); p.x += centeroid.x; p.y += centeroid.y; p.z += centeroid.z; @@ -404,6 +702,8 @@ void Spriteset_MapDoom::line(Point p1, Point p2) { float length = std::sqrt(dx * dx + dy * dy); float angle = std::atan2(dy, dx); + //Output::Debug(". {}", length); + for (float i = 0; i < length; i++) { float zz = z1 + std::tanf(angle) * i; @@ -411,6 +711,7 @@ void Spriteset_MapDoom::line(Point p1, Point p2) { zz = lerp(z1, z2, f); pixel(x1 + std::cosf(angle) * i, y1 + std::sin(angle) * i, zz, p1.color); + // Output::Debug(".."); } } @@ -486,6 +787,7 @@ void Spriteset_MapDoom::drawPolygon(std::vector vertic for (size_t i = 0; i + 1 < intersections.size(); i += 2) { int x_start = intersections[i]; int x_end = intersections[i + 1]; + // TODO Remplacer pr la fonction line ? for (int x = x_start; x <= x_end; ++x) { pixel(x, y, z, color); // Dessiner les pixels dans l'intervalle } @@ -555,6 +857,8 @@ bool Spriteset_MapDoom::comparePoints(const Point& p1, const Point& p2) { void Spriteset_MapDoom::Show() { + //Output::Debug("Start render"); + sprite->Clear(); spriteUpper->Clear(); @@ -581,6 +885,8 @@ void Spriteset_MapDoom::Show() { Color c = Color(255,0,0,255); for (auto p : points) { + //Output::Debug("AZE"); + int i = p.x + 999 / 2; int j = p.y + 999 / 2; @@ -598,10 +904,10 @@ void Spriteset_MapDoom::Show() { green = p.color.green; blue = p.color.blue; - //Output::Debug(" {} {} {}", red, green, blue); + // Output::Debug(" {} {} {}", red, green, blue); c = Color(red * mult / 100, green * mult / 100, blue * mult / 100, 255); - //c = p.color; + sprite->FillRect(r, c); if (p.upper) { @@ -610,7 +916,7 @@ void Spriteset_MapDoom::Show() { } } } - + //Output::Debug("Rendered"); } diff --git a/src/spritesetmap_doom.h b/src/spritesetmap_doom.h index 86181c4ded..bbbc22aef6 100644 --- a/src/spritesetmap_doom.h +++ b/src/spritesetmap_doom.h @@ -4,10 +4,42 @@ #include #include #include "bitmap.h" +#include +#include "async_handler.h" +#include "sprite.h" class Spriteset_MapDoom { public: + bool doomMap = false; + int map[999][999]; + + int mapW, mapH = 0; + + // Structure représentant le joueur + struct PlayerDoom { + float x, y; // Position du joueur + float angle; // Angle de vue (orientation du joueur) + float fov; // Champ de vision du joueur (Field of View) + }; + PlayerDoom player = { 10 / 2.0 * TILE_SIZE, 8 / 2.0 * TILE_SIZE, 0, 110.0f * (M_PI / 180.0f) }; + + float castRay(float rayAngle, int &ray); + void renderScene(); + void renderFloorAndCeiling(float playerX, float playerY, float playerAngle); + + void renderTexturedFloor(float playerX, float playerY, float playerAngle); + BitmapRef mapTexture(int x, int y); + void OnTitleSpriteReady(FileRequestResult* result, int i); + BitmapRef bitmap; + BitmapRef bitmap2; + FileRequestBinding request_id; + + std::unique_ptr tilemap; + + + int mapWidth(); + int mapHeight(); struct vec3 { float x, y, z = 0;