Skip to content

Instantly share code, notes, and snippets.

@DenisBelmondo
Created August 19, 2025 21:05
Show Gist options
  • Save DenisBelmondo/64611b8f824b04d1e3aa5e9e442749ed to your computer and use it in GitHub Desktop.
Save DenisBelmondo/64611b8f824b04d1e3aa5e9e442749ed to your computer and use it in GitHub Desktop.
#include <cmath>
#include <cstdio>
#include <raylib.h>
#include <raymath.h>
#include <vector>
static const auto TICK_RATE = 1.0 / 30.0;
static Vector2 playerPosition { 5, 5 };
static Vector2 playerDirection { 0, -1 };
static Vector2 playerVelocity;
static std::vector<int> plane;
static std::size_t planePitch;
static Camera3D camera {
.position = {},
.target = {},
.up = { 0, 1, 0 },
.fovy = 75,
.projection = CAMERA_PERSPECTIVE,
};
static const auto WALL_VERTEX_SHADER_SOURCE = R"(
#version 330
// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec4 vertexColor;
// Input uniform values
uniform mat4 mvp;
// Output vertex attributes (to fragment shader)
out vec2 fragTexCoord;
out vec4 fragColor;
out vec3 fragVertexNormal;
// NOTE: Add your custom variables here
void main() {
// Send vertex attributes to fragment shader
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
fragVertexNormal = vertexNormal;
// Calculate final vertex position
gl_Position = mvp * vec4(vertexPosition, 1.0);
}
)";
static const auto WALL_FRAGMENT_SHADER_SOURCE = R"(
#version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
in vec3 fragVertexNormal;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Output fragment color
out vec4 finalColor;
// NOTE: Add your custom variables here
void main() {
// Texel color fetching from texture sampler
vec4 texelColor = texture(texture0, fragTexCoord);
// TODO: hsv
float shade = abs(dot(fragVertexNormal, vec3(0.5, 1, 1)));
vec4 sshade = vec4(shade, shade, shade, 1.0);
// final color is the color from the texture
// times the tint color (colDiffuse)
// times the fragment color (interpolated vertex color)
finalColor = texelColor * colDiffuse * fragColor * sshade;
}
)";
static RenderTexture renderTexture;
static Mesh wallMesh;
static Texture pistolTexture;
static Image wallImage000;
static Texture wallTexture000;
static Material wallMaterial;
static void tick(double deltaTime) {
float lookAxis = IsKeyDown(KEY_RIGHT) - IsKeyDown(KEY_LEFT);
float forwardAxis = IsKeyDown(KEY_W) - IsKeyDown(KEY_S);
float strafeAxis = IsKeyDown(KEY_D) - IsKeyDown(KEY_A);
Vector2 move {};
lookAxis *= 3;
lookAxis *= deltaTime;
playerDirection = Vector2Rotate(playerDirection, lookAxis);
move += playerDirection * forwardAxis;
move += Vector2 { -playerDirection.y, playerDirection.x } * strafeAxis;
move = Vector2Normalize(move);
move *= 2;
move *= deltaTime;
playerVelocity += move;
auto oldPlayerPosition = playerPosition;
playerPosition += playerVelocity;
if (plane[int(playerPosition.y + 0.5f) * planePitch + int(playerPosition.x + 0.5f)]) {
playerPosition = oldPlayerPosition;
}
playerVelocity = Vector2Lerp(playerVelocity, Vector2Zero(), 10 * deltaTime);
}
int main() {
plane = {
31, 15, 7, 3, 1, 32, 16, 8, 4, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
planePitch = std::sqrt(plane.size());
InitWindow(640, 480, "Wolfenstein 3D");
renderTexture = LoadRenderTexture(640, 480);
wallMesh = GenMeshCube(1, 1, 1);
pistolTexture = LoadTexture("static/textures/pistol.png");
wallImage000 = LoadImage("static/textures/wall_000.png");
ImageFlipVertical(&wallImage000);
wallTexture000 = LoadTextureFromImage(wallImage000);
wallMaterial = LoadMaterialDefault();
wallMaterial.shader = LoadShaderFromMemory(WALL_VERTEX_SHADER_SOURCE, WALL_FRAGMENT_SHADER_SOURCE);
wallMaterial.maps[MATERIAL_MAP_DIFFUSE].color = WHITE;
wallMaterial.maps[MATERIAL_MAP_DIFFUSE].texture = wallTexture000;
double previousTime = GetTime();
double lag = 0.0;
while (!WindowShouldClose()) {
double currentTime = GetTime();
double deltaTime = currentTime - previousTime;
previousTime = currentTime;
lag += deltaTime;
while (lag >= TICK_RATE) {
tick(TICK_RATE);
lag -= TICK_RATE;
}
BeginTextureMode(renderTexture); {
ClearBackground(BLACK);
DrawRectangle(0, 0, 640, 240, { 114, 114, 114, 255 });
DrawRectangle(0, 241, 640, 480, { 32, 32, 32, 255 });
camera.position = { playerPosition.x, 0, playerPosition.y };
camera.target = Vector3Add(camera.position, { playerDirection.x, 0, playerDirection.y });
BeginMode3D(camera); {
for (std::size_t i = 0; i < plane.size(); i++) {
float x = float(i % planePitch);
float y = std::floor(i / float(planePitch));
for (int j = plane[i], k = 0; j > 0; j >>= 1, k++) {
if (j & 1) {
DrawMesh(wallMesh, wallMaterial, MatrixTranslate(x, k, y));
}
}
}
} EndMode3D();
} EndTextureMode();
BeginDrawing();
DrawTexturePro(renderTexture.texture, { 0, 0, float(renderTexture.texture.width), float(-renderTexture.texture.height) }, { 0, 0, 640, 480 }, {}, 0, WHITE);
EndDrawing();
}
UnloadMaterial(wallMaterial);
UnloadTexture(pistolTexture);
UnloadTexture(wallTexture000);
UnloadImage(wallImage000);
UnloadMesh(wallMesh);
UnloadRenderTexture(renderTexture);
CloseWindow();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment