mpfw/mpfw/main.cpp

451 lines
12 KiB
C++

#include <iostream>
#include <raylib.h>
#include <raymath.h>
#include <fstream>
#include <sstream>
#include <string>
#include "MPFW_Quake.h"
#include "MPFW_Console.h"
#include <print>
#include <rlgl.h>
#include <thread>
// turn quake miptex into rl texture
Texture2D RLMT_QUAKE(MPFW::Quake::Maps::rlMipTex rlmt) {
Texture2D retval;
retval.id = rlmt.glTextureID;
retval.width = rlmt.width;
retval.height = rlmt.height;
retval.format = rlmt.type;
return retval;
}
Camera camera = { 0 };
Vector3 rotation = { 1,0,0 };
Vector3 hRotation = { 1,0,0 };
Vector3 velocity = { 0,0,0 };
float accelFactor = 300.0f;
struct ConsoleSettings {
int height;
};
// this is grossly imprecise because of a lack of direct interfaces
// with the loop, but it's simple and should be performant in a
// thread
//static void __DebugCounter_Quake(MPFW::Quake::Maps::MapFile* mapFile) {
// while (mapFile->ds != MPFW::Quake::Maps::Debug::DONE) {
// switch (mapFile->ds) {
// case MPFW::Quake::Maps::Debug::HEADER:
// std::print("Reading header\n");
// break;
// case MPFW::Quake::Maps::Debug::MODELS:
// std::print("Model {}/{}\n", mapFile->modelsCDBG, mapFile->data.header.models.size / 64);
// break;
// case MPFW::Quake::Maps::Debug::VERTICES:
// std::print("Vertex {}/{}\n", mapFile->verticesCDBG, mapFile->data.header.vertices.size / 12);
// break;
// case MPFW::Quake::Maps::Debug::EDGES:
// std::print("Edge {}/{}\n", mapFile->edgesCDBG, mapFile->data.header.edges.size / 4);
// break;
// case MPFW::Quake::Maps::Debug::TEXINFO:
// std::print("Surface {}/{}\n", mapFile->texInfoCDBG, mapFile->data.header.texinfo.size / 40);
// break;
// case MPFW::Quake::Maps::Debug::LEDGES:
// std::print("Ledge {}/{}\n", mapFile->data.ledges.size(), mapFile->data.header.ledges.size / 2);
// break;
// case MPFW::Quake::Maps::Debug::FACES:
// std::print("Face {}/{}\n", mapFile->data.faces.size(), mapFile->data.header.faces.size / 20);
// break;
// }
//#pragma warning(suppress : 4996)
// _sleep(250);
// }
//}
void Look() {
hRotation = Vector3RotateByAxisAngle(hRotation, { 0,1,0 }, -GetMouseDelta().x * GetFrameTime());
rotation = Vector3RotateByAxisAngle(rotation, { 0,1,0 }, -GetMouseDelta().x * GetFrameTime());
rotation = Vector3Normalize({ rotation.x, Clamp(rotation.y - GetMouseDelta().y * GetFrameTime(), -0.99, 0.99), rotation.z });
}
void AirAccelerate(bool inAir) {
if (IsKeyDown(KEY_W)) {
velocity += hRotation * GetFrameTime() * accelFactor * (IsKeyDown(KEY_LEFT_SHIFT) ? 4 : 2);
}
if (IsKeyDown(KEY_S)) {
velocity -= hRotation * GetFrameTime() * accelFactor;
}
Vector3 sideRotation = Vector3RotateByAxisAngle(hRotation, { 0,1,0 }, DEG2RAD * 90);
if (IsKeyDown(KEY_A)) {
velocity += sideRotation * GetFrameTime() * accelFactor * (IsKeyDown(KEY_LEFT_SHIFT) ? 4 : 2);
}
if (IsKeyDown(KEY_D)) {
velocity -= sideRotation * GetFrameTime() * accelFactor * (IsKeyDown(KEY_LEFT_SHIFT) ? 4 : 2);
}
if (inAir)velocity.y -= GetFrameTime() * 2.5;
velocity.x *= 80 * GetFrameTime();
velocity.z *= 80 * GetFrameTime();
}
void Accelerate() {
if (IsKeyDown(KEY_SPACE)) velocity.y += accelFactor * 0.0025;
AirAccelerate(false);
if (velocity.y < 0) velocity.y = 0;
}
#ifdef _DEBUG
template <typename T>
void ___test___(T a, T b) {
if (a != b) throw;
}
#endif
int main() {
#ifdef _DEBUG
std::print("COMPILED IN DEBUG MODE\n----------------------\n\n");
std::print("Unit testing\n\n\n");
{ // UT01 : formatting a quake map directory entry
std::print("UT01 : formatting a quake map directory entry\n");
MPFW::Quake::Maps::DirectoryEntry dirent;
dirent.offset = 1000;
dirent.size = 2000;
std::string retval = std::format("{}", dirent);
std::print("{}", retval);
___test___(retval, std::string("([MPFW::Quake::Maps::DirectoryEntry]: at pos 1000, 2000B in size)"));
std::println();
std::print("UT01 Success\n");
}
std::print("\nEnd of unit testing\n\n\n");
#endif
MPFW::Quake::Maps::MapFile map;
// std::thread t(__DebugCounter_Quake, &map);
// t.detach();
std::vector<Color> colors;
for (int i = 0; i < 3000000; i++) {
colors.push_back({ (unsigned char)GetRandomValue(0, 255), (unsigned char)GetRandomValue(0, 255), (unsigned char)GetRandomValue(0, 255), 255 });
}
std::print("MAP DATA:\n---------\n\n");
std::print("Version: {}\n", map.data.header.version);
std::print("\n---\nDIRENTS\n-------\n");
std::print("Entities: {}\n", map.data.header.entities);
std::print("Planes: {}\n", map.data.header.planes);
std::print("Wall Textures (miptex): {}\n", map.data.header.miptex);
std::print("Map Vertices: {}\n", map.data.header.vertices);
std::print("Leaves Visibility Lists: {}\n", map.data.header.visilist);
std::print("BSP Nodes: {}\n", map.data.header.nodes);
std::print("Texture Info for Faces: {}\n", map.data.header.texinfo);
std::print("Faces of each surface: {}\n", map.data.header.faces);
std::print("Wall Lightmaps: {}\n", map.data.header.lightmaps);
std::print("Clip Nodes: {}\n", map.data.header.clipnodes);
std::print("BSP Leaves: {}\n", map.data.header.leaves);
std::print("List of Faces: {}\n", map.data.header.lface);
std::print("Edges of Faces: {}\n", map.data.header.edges);
std::print("List of Edges: {}\n", map.data.header.ledges);
std::print("Models: {}\n", map.data.header.models);
std::print("---\n\n");
std::print("Vertex count: {} (on {} in header)\n", map.data.vertices.size(), map.data.header.vertices.size / sizeof(Vector3));
std::print("Edge count: {} (on {} in header)\n", map.data.edges.size(), map.data.header.edges.size / 4);
std::print("Model count: {} (on {} in header)\n", map.data.models.size(), map.data.header.models.size / sizeof(MPFW::Quake::Maps::qModel));
for (int i = 0; i < map.data.models.size(); i++) {
if (map.data.models[i].node_id3 != 0) {
std::print("node 3 on {} isn't 0 ({})\n", i, map.data.models[i].node_id3);
}
}
map.pal = new MPFW::Quake::Maps::Palette("data/palette.lmp");
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(1280, 720, TextFormat("mpfw"));
// SetTargetFPS(60);
SetExitKey(0);
DisableCursor();
MPFW::Console::CommandHandlerResources chr;
chr.mapQuake = &map;
MPFW::Console::CommandHandler cmdH(&chr);
Font robotoMonoRegular = LoadFontEx("data/fonts/RobotoMono/RobotoMono-Regular.ttf", 30, NULL, 6000);
int robotoMonoHeight = MeasureTextEx(robotoMonoRegular, "X", 30, 0).y;
cmdH.RunScript("data/cfg/startup.cfg");
// rlSetClipPlanes(1, INFINITY);
camera.position = { 0,5,0 };
camera.target = { 1,0,0 };
camera.fovy = 120;
camera.up = { 0,1,0 };
camera.projection = CAMERA_PERSPECTIVE;
bool indivFaceMode = false;
int indivFace = 0;
bool consoleOn = false;
std::string cmdBuf = "";
while (!WindowShouldClose()) {
if (IsKeyPressed(KEY_APOSTROPHE)) {
consoleOn = !consoleOn;
}
if(!consoleOn){
Look();
if (camera.position.y > 5) AirAccelerate(true);
else Accelerate();
if (camera.position.y < 5) camera.position.y = 5;
if (IsKeyPressed(KEY_LEFT) && indivFace > 0) indivFace--;
if (IsKeyPressed(KEY_RIGHT) && indivFace < map.data.faces.size() - 1) indivFace++;
if (IsKeyPressed(KEY_F)) indivFaceMode = !indivFaceMode;
}
camera.position += velocity;
camera.target = camera.position + rotation;
BeginDrawing();
ClearBackground(BLACK);
DrawRectangleGradientV(0, 0, GetScreenWidth(), GetScreenHeight(), WHITE, LIGHTGRAY);
BeginMode3D(camera);
// DrawGrid(1000, 10);
if (!indivFaceMode) {
for (int i = 0; i < map.data.renderFaces.size(); i++) {
rlColor4ub(255, 255, 255, 255);
rlSetTexture(map.data.renderFaces[i].glTextureId);
for (int j = 1; j < map.data.renderFaces[i].vertices.size(); j++) {
rlBegin(RL_QUADS); // for texturing reasons because rlgl
Vector3 a = map.data.renderFaces[i].vertices[0],
b = map.data.renderFaces[i].vertices[j],
c = map.data.renderFaces[i].vertices[j - 1];
Vector2 at = map.data.renderFaces[i].texCoords[0],
bt = map.data.renderFaces[i].texCoords[j],
ct = map.data.renderFaces[i].texCoords[j - 1];
rlTexCoord2f(at.x, at.y);
rlVertex3f(a.x, a.y, a.z);
rlTexCoord2f(bt.x, bt.y);
rlVertex3f(b.x, b.y, b.z);
rlTexCoord2f(ct.x, ct.y);
rlVertex3f(c.x, c.y, c.z);
rlVertex3f(c.x, c.y, c.z);
rlEnd();
}
}
}
else {
int i = indivFace;
std::vector<Vector3> vertices;
rlColor4ub(colors[i].r, colors[i].g, colors[i].b, colors[i].a);
rlBegin(RL_TRIANGLES);
Vector3 a = MPFW::Quake::Maps::qVec2RLVec(map.data.vertices[map.data.edges[abs(map.data.ledges[map.data.faces[i].ledgeId])].vertex0]);
for (int k = 0; k < map.data.faces[i].ledgeNum; k++) {
if (map.data.ledges[map.data.faces[i].ledgeId + k] < 0) {
vertices.push_back(MPFW::Quake::Maps::qVec2RLVec(
map.data.vertices[
map.data.edges[
abs(
map.data.ledges[
map.data.faces[i].ledgeId + k
]
)
].vertex1
]
));
}
else {
vertices.push_back(MPFW::Quake::Maps::qVec2RLVec(
map.data.vertices[
map.data.edges[
abs(
map.data.ledges[
map.data.faces[i].ledgeId + k
]
)
].vertex0
]
));
}
DrawLine3D(MPFW::Quake::Maps::qVec2RLVec(
map.data.vertices[
map.data.edges[
abs(
map.data.ledges[
map.data.faces[i].ledgeId + k
]
)
].vertex0
]
),
MPFW::Quake::Maps::qVec2RLVec(
map.data.vertices[
map.data.edges[
abs(
map.data.ledges[
map.data.faces[i].ledgeId + k
]
)
].vertex1
]
), RED);
}
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
rlEnd();
rlColor4f(255, 255, 255, 255);
}
EndMode3D();
DrawFPS(0, 0);
if (indivFaceMode) {
std::vector<Vector3> vertices;
{
int i = indivFace;
rlColor4ub(colors[i].r, colors[i].g, colors[i].b, colors[i].a);
rlBegin(RL_TRIANGLES);
Vector3 a = MPFW::Quake::Maps::qVec2RLVec(map.data.vertices[map.data.edges[abs(map.data.ledges[map.data.faces[i].ledgeId])].vertex0]);
for (int k = 0; k < map.data.faces[i].ledgeNum; k++) {
if (map.data.ledges[map.data.faces[i].ledgeId + k] < 0) {
vertices.push_back(MPFW::Quake::Maps::qVec2RLVec(
map.data.vertices[
map.data.edges[
abs(
map.data.ledges[
map.data.faces[i].ledgeId + k
]
)
].vertex1
]
));
}
else {
vertices.push_back(MPFW::Quake::Maps::qVec2RLVec(
map.data.vertices[
map.data.edges[
abs(
map.data.ledges[
map.data.faces[i].ledgeId + k
]
)
].vertex0
]
));
}
}
}
DrawText(TextFormat("Current face: %i", indivFace), 0, 30, 30, BLACK);
for (int i = 0; i < vertices.size(); i++) {
DrawText(TextFormat("Vertex %i : %f %f %f", i, vertices[i].x, vertices[i].y, vertices[i].z), 0, 60 + 10 * i, 10, BLACK);
}
}
if (consoleOn) {
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight() / 2, {0,0,0,200});
DrawTextEx(robotoMonoRegular, cmdH.logStr.c_str(), { 0, GetScreenHeight() / 2 - MeasureTextEx(robotoMonoRegular, cmdH.logStr.c_str(), 20, 0).y }, 20, 0, WHITE);
DrawRectangle(0, GetScreenHeight() / 2, GetScreenWidth(), 20, { 0,0,0,200 });
DrawLine(0, GetScreenHeight() / 2, GetScreenWidth(), GetScreenHeight() / 2, GOLD);
DrawTextEx(robotoMonoRegular, cmdBuf.c_str(), { 0, (float)GetScreenHeight() / 2 }, 20, 0, GRAY);
int key = GetCharPressed();
while (key > 0) {
if ((key >= 32) && (key <= 126)) {
cmdBuf += (char)key;
}
key = GetCharPressed();
}
if (IsKeyPressed(KEY_BACKSPACE) && cmdBuf != "") cmdBuf.pop_back();
if (IsKeyPressed(KEY_ENTER)) {
cmdH.Run(cmdBuf);
cmdBuf = "";
}
}
EndDrawing();
}
CloseWindow();
}