Compare commits

...

13 Commits

Author SHA1 Message Date
3af24e812f Added music and jumpscares 2025-09-13 21:17:56 -05:00
27b2ee70d1 acorn is now collectable 2025-09-13 20:16:40 -05:00
8caf00c004 fixed the acorn color 2025-09-13 19:29:36 -05:00
d0eb63ba03 My first Blender model- Acorn 2025-09-13 19:16:33 -05:00
28f5bde1bc Added peripheral boundaries with stone walls 2025-09-13 15:35:31 -05:00
56fa075716 collision mechanics 2025-09-13 14:13:27 -05:00
8417f8855a Added moving fence. 2025-09-13 11:43:03 -05:00
899cf9db8b Adding resources and tweaks 2025-09-13 10:24:08 -05:00
123c374ab4 Tree transparency fix 2025-09-01 15:49:07 -05:00
4a4d198617 Added zombie for testing 2025-08-31 22:55:58 -05:00
d7363921ad Basic flashlight 2025-08-31 22:08:18 -05:00
a1fede92f3 Cleaning up code. 2025-08-31 19:02:18 -05:00
b580a34999 Variable fog of war 2025-08-31 18:00:03 -05:00
303 changed files with 34280 additions and 89 deletions

569
main.c
View File

@@ -5,8 +5,8 @@
#include "stddef.h"
#include "stdlib.h"
#include "stdint.h"
#include "time.h"
#include "rlgl.h"
#include "float.h"
//----------------------------------------------------------------------------------
// Defines and Macros
@@ -37,6 +37,9 @@
#define FLOOR_EXTENT 25
#define TILE_SIZE 5.0f
#define PLAYER_RADIUS 0.5f
#define PLAYER_HEIGHT 1.8f
enum game_state {
STATE_MENU, // 0 by default
STATE_GAME, // 1
@@ -71,9 +74,6 @@ static inline float hash01_to_m05p05(uint32_t h_bits)
//----------------------------------------------------------------------------------
//Defining program structure
//----------------------------------------------------------------------------------
//bob
typedef struct
{
Camera camera; // <- now part of the game state
@@ -97,22 +97,13 @@ typedef struct
enum game_state state;
int shouldExit;
Player player;
} Master;
int nearAcorn;
int isJumpscared;
float jumpscareTimer;
// GLSL 330 core fragment shader (desktop)
// Discards fragments with alpha below a threshold so depth is only written on real pixels.
static const char *ALPHA_CLIP_FS =
"#version 330 core\n"
"in vec2 fragTexCoord;\n"
"in vec4 fragColor;\n"
"uniform sampler2D texture0;\n"
"uniform float u_alphaCutoff; // e.g., 0.3\n"
"out vec4 finalColor;\n"
"void main(){\n"
" vec4 texel = texture(texture0, fragTexCoord);\n"
" if(texel.a < u_alphaCutoff) discard;\n"
" finalColor = texel * fragColor;\n"
"}\n";
Sound jumpScare;
Music bgm;
} Master;
//------------------------------------------------------------------------------------
// Function Initation
@@ -126,6 +117,18 @@ static void DrawLevel(Model mdlTile);
static void CenterMouseAndFlush(void);
int Random(int x);
static void RenderTrees(Master* g, Texture2D tree, Vector3 treepos, float treeSize);
static void ApplyFogShaderToModel(Model *m, Shader fog);
static BoundingBox MakeModelWorldAABB(Model m, Vector3 pos, Vector3 scale, float yawDeg);
static BoundingBox PlayerAABB(Vector3 p);
static void ResolveAgainstBoxXZ(Master* g, BoundingBox box);
static float ModelLengthXUnits(Model m);
static float ModelLengthZUnits(Model m);
static void DrawPerimeter(Model wall, float border, float scale);
static void CollidePerimeter(Master* g, Model wall, float border, float scale); // optional
float square(float num);
//------------------------------------------------------------------------------------
// Program main entry point
@@ -138,6 +141,9 @@ int main(void)
const int screenWidth = 1440*2;
const int screenHeight = 960*2;
// BEFORE InitWindow (optional but nice): enable MSAA for smoother alpha edges
SetConfigFlags(FLAG_MSAA_4X_HINT);
InitWindow(screenWidth, screenHeight, "raylib");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
ToggleFullscreen();
@@ -153,8 +159,10 @@ int main(void)
g.index = 0;
g.state = STATE_MENU;
g.shouldExit = 0;
g.nearAcorn = 0;
g.isJumpscared = 0;
//Define
//Define player values
g.player.sensitivity = (Vector2){ 0.001f, 0.001f };
g.player.lookRotation = (Vector2){ 0 };
g.player.headTimer = 0.0f;
@@ -169,26 +177,36 @@ int main(void)
g.player.position.y + (BOTTOM_HEIGHT + g.player.headLerp),
g.player.position.z,
};
//g.player.camera.target = (Vector3){ 0.0f, 0.0f, 1.0f }; // Camera target
g.player.camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Up vector
g.player.camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
g.player.camera.fovy = 60.0f;
g.player.camera.projection = CAMERA_PERSPECTIVE;
g.player.cameraMode = CAMERA_FIRST_PERSON;
UpdateCameraAngle(&g);
// Load GLTF model (no animations)
//Model model = LoadModel("resources/3d_models/bad_sphere.glb");
//Vector3 position = { 0.0f, 0.0f, 0.0f };
//Model wall = LoadModel("resources/3d_models/Tiny_Treats_Homely_House_1.0_FREE/Assets/gltf/fence_straight.gltf");
Model wall = LoadModel("resources/3d_models/RuinsGLB/Walls/WallNormalXL.glb");
Vector3 wall_position = { 10.0f, 0.0f, 0.0f };
float wall_yaw = 0.0f; // rotate around Y
float wall_pitch = 0.0f; // rotate around X
float wall_roll = 0.0f; // rotate around Z
Model acorn = LoadModel("resources/3d_models/my_models/my_acorn.glb");
Vector3 acorn_position = { 0.0f, 0.0f, -9.0f };
float acorn_yaw = 0.0f; // rotate around Y
float acorn_pitch = 0.0f; // rotate around X
float acorn_roll = 0.0f; // rotate around Z
// Load a 2D image as texture for the billboard
//Billboards always point toward the active camera.
Texture2D sign = LoadTexture("resources/sprites/diard-charles.jpg");
Texture2D sign = LoadTexture("resources/sprites/husk/ZOMBC1.png");
//Texture2D sign = LoadTexture("resources/sprites/diard-charles.jpg");
GenTextureMipmaps(&sign);
SetTextureFilter(sign, TEXTURE_FILTER_BILINEAR); // optional but looks nicer
Vector3 bbPos = (Vector3){ 1.0f, 2.5f, 1.0f }; // where in 3D world to place it
float bbSize = 5.0f; // billboard height in world units
SetTextureFilter(sign, TEXTURE_FILTER_POINT); // optional but looks nicer
Vector3 bbPos = (Vector3){ -1.0f, 2.0f, -1.0f }; // where in 3D world to place it
float bbSize = 4.0f; // billboard height in world units
// Load a 2D image as texture for the billboard
//Billboards always point toward the active camera.
@@ -197,54 +215,41 @@ int main(void)
SetTextureFilter(tree, TEXTURE_FILTER_BILINEAR); // optional but looks nicer
Vector3 treepos = (Vector3){ 0.0f, 0.0f, 0.0f }; // where in 3D world to place it
float treeSize = 15.0f; // billboard height in world units
float cutoffAlpha = 0.7f; //Needs to be aggressive to remove the alpha.
// --- Grass tile setup ---
Texture2D texGrass = LoadTexture("resources/textures/grass_textures/Grass_01.png"); // adjust path
// Grass tile setup
Texture2D texGrass = LoadTexture("resources/textures/grass_textures/Grass_01.png");
GenTextureMipmaps(&texGrass);
SetTextureFilter(texGrass, TEXTURE_FILTER_TRILINEAR); // nicer at angles
SetTextureWrap(texGrass, TEXTURE_WRAP_REPEAT);
// A 3D plane (centered at origin) of size tileSize x tileSize
const float tileSize = 5.0f; // match your DrawLevel tileSize
const float tileSize = TILE_SIZE;
Mesh meshTile = GenMeshPlane(tileSize, tileSize, 1, 1);
Model mdlTile = LoadModelFromMesh(meshTile);
mdlTile.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = texGrass;
Shader shAlphaClip = LoadShaderFromMemory(NULL, ALPHA_CLIP_FS);
int locCutoff = GetShaderLocation(shAlphaClip, "u_alphaCutoff");
float cutoff = 0.3f; // tweak to taste; 0.3 - 0.5 works well for tree PNGs
SetShaderValue(shAlphaClip, locCutoff, &cutoff, SHADER_UNIFORM_FLOAT);
// --- Skybox setup ---
// Generate cube mesh
Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f);
Model skybox = LoadModelFromMesh(cube);
// Load skybox shader
// Make sure the .vs/.fs are in your resources/shaders/glsl330/ folder
Shader skyboxShader = LoadShader(
"resources/shaders/skybox.vs",
"resources/shaders/skybox.fs"
Shader skyboxShader = LoadShader
(
"shaders/skybox.vs",
"shaders/skybox.fs"
);
// Attach shader to skybox
skybox.materials[0].shader = skyboxShader;
// Load your cubemap (cross layout image)
Image img = LoadImage("resources/cubemap/cubemap.png");
// AUTO_DETECT will figure out layout (works for cross 4x3, panorama, etc.)
skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture =
LoadTextureCubemap(img, CUBEMAP_LAYOUT_AUTO_DETECT);
UnloadImage(img);
skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(img, CUBEMAP_LAYOUT_AUTO_DETECT);
UnloadImage(img); //no longer need image loaded.
// Tell the shader which material map is the environmentMap
int mapType = MATERIAL_MAP_CUBEMAP;
SetShaderValue(skyboxShader,
GetShaderLocation(skyboxShader, "environmentMap"),
&mapType, SHADER_UNIFORM_INT);
SetShaderValue(skyboxShader, GetShaderLocation(skyboxShader, "environmentMap"), &mapType, SHADER_UNIFORM_INT);
//Flip/gamma options (set to 0 for PNG cross)
int vflipped = 0;
@@ -252,12 +257,85 @@ int main(void)
SetShaderValue(skyboxShader, GetShaderLocation(skyboxShader, "vflipped"), &vflipped, SHADER_UNIFORM_INT);
SetShaderValue(skyboxShader, GetShaderLocation(skyboxShader, "doGamma"), &doGamma, SHADER_UNIFORM_INT);
// Done now you can draw it
// Load the fog shader
Shader fog = LoadShader("shaders/fog.vs", "shaders/fog.fs");
// Grab uniform locations (cache them)
int locPlayer = GetShaderLocation(fog, "u_playerPos");
int locRadius = GetShaderLocation(fog, "u_fogRadius");
int locFeather = GetShaderLocation(fog, "u_fogFeather");
int locFogColor = GetShaderLocation(fog, "u_fogColor");
int locCutoff_fog = GetShaderLocation(fog, "u_alphaCutoff");
int locInner = GetShaderLocation(fog, "u_inner");
int locOuter = GetShaderLocation(fog, "u_outer");
int locMinShadow = GetShaderLocation(fog, "u_minShadow");
// Optional if you added the sharpness curve in the shader
int locSharpness = GetShaderLocation(fog, "u_sharpness");
//Flashlight
int locSpotDir = GetShaderLocation(fog, "u_spotDir");
int locSpotCos = GetShaderLocation(fog, "u_spotCos");
int locSpotSoft = GetShaderLocation(fog, "u_spotSoft");
int locLightRange = GetShaderLocation(fog, "u_lightRange");
int locLightFade = GetShaderLocation(fog, "u_lightFade");
int locIntensity = GetShaderLocation(fog, "u_intensity");
int locBeamSpread = GetShaderLocation(fog, "u_beamSpread");
// Let raylib know which matrices the shader expects
fog.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(fog, "matModel");
fog.locs[SHADER_LOC_MATRIX_VIEW] = GetShaderLocation(fog, "matView");
fog.locs[SHADER_LOC_MATRIX_PROJECTION] = GetShaderLocation(fog, "matProjection");
// --- Apply shader to your ground tile model ---
mdlTile.materials[0].shader = fog; // same shader also works for opaque
//Apply shader to wall
ApplyFogShaderToModel(&wall, fog);
ApplyFogShaderToModel(&acorn, fog);
// Defaults for opaque geometry (no alpha cut)
float cutoffOpaque = 0.0f;
SetShaderValue(fog, locCutoff_fog, &cutoffOpaque, SHADER_UNIFORM_FLOAT);
// Fog/vignette tuning
float inner = 0.0f; // start radius (center under player)
float outer = 20.0f; // how far until full fog
float minShadow = 0.85f; // baseline darkness at the center (0 = none, 1 = pitch black)
float sharpness = 2.0f; // steeper edge (optional if shader uses it)
Vector4 fogColor = {0.0f, 0.0f, 0.0f, 1.0f};
// Flashligh tuning
float spotAngleDeg = 35.0f; //cone angle
float spotCos = cosf(DEG2RAD * (spotAngleDeg * 0.5f));
float spotSoft = 0.10f;
float lightRange = 150.0f;//100.0f;
float lightFade = 1.0f;
float intensity = 0.25f; // try 0.71.5 to taste
float beamSpread = 0.05f; // try 0.150.35; higher = less “laser” at distance
SetShaderValue(fog, locIntensity, &intensity, SHADER_UNIFORM_FLOAT);
SetShaderValue(fog, locBeamSpread, &beamSpread, SHADER_UNIFORM_FLOAT);
SetShaderValue(fog, locSpotCos, &spotCos, SHADER_UNIFORM_FLOAT);
SetShaderValue(fog, locSpotSoft, &spotSoft, SHADER_UNIFORM_FLOAT);
SetShaderValue(fog, locLightRange, &lightRange, SHADER_UNIFORM_FLOAT);
SetShaderValue(fog, locLightFade, &lightFade, SHADER_UNIFORM_FLOAT);
SetShaderValue(fog, locInner, &inner, SHADER_UNIFORM_FLOAT);
SetShaderValue(fog, locOuter, &outer, SHADER_UNIFORM_FLOAT);
SetShaderValue(fog, locMinShadow, &minShadow, SHADER_UNIFORM_FLOAT);
SetShaderValue(fog, locFogColor, &fogColor, SHADER_UNIFORM_VEC4);
SetShaderValue(fog, locSharpness, &sharpness, SHADER_UNIFORM_FLOAT);
//Music and audio
InitAudioDevice();
g.jumpScare = LoadSound("resources/sound_effects/fnaf.wav");
SetSoundVolume(g.jumpScare, 0.8);
g.bgm = LoadMusicStream("resources/music/background.mp3");
SetMusicVolume(g.bgm, 0.4f);
PlayMusicStream(g.bgm);
//--------------------------------------------------------------------------------------
// Main game loop
@@ -318,6 +396,62 @@ int main(void)
bool crouching = IsKeyDown(KEY_LEFT_CONTROL);
UpdateBody(&g, g.player.lookRotation.x, sideway, forward, IsKeyDown(KEY_SPACE), crouching);
// Build wall collider (scale must match your DrawModelEx scale)
BoundingBox acornBox = MakeModelWorldAABB(acorn, acorn_position, (Vector3){0.25,0.25,0.25}, acorn_yaw);
// Collide player vs wall (XZ slide)
ResolveAgainstBoxXZ(&g, acornBox);
int player_acorn_diff = square(g.player.position.x - acorn_position.x) + square(g.player.position.z - acorn_position.z);
if (player_acorn_diff <= 3)
{
g.nearAcorn = 1;
}
else
{
g.nearAcorn = 0;
}
if (g.nearAcorn == 1 && IsKeyPressed(KEY_E))
{
acorn_position.x = 15;
acorn_position.z = 15;
g.isJumpscared = 1;
g.jumpscareTimer = 5.0f; // show overlay for 1s
PlaySound(g.jumpScare); // <-- trigger ONCE here
}
if (g.isJumpscared == 1)
{
g.jumpscareTimer -= GetFrameTime();
if (g.jumpscareTimer <= 0.0f) g.isJumpscared = 0;
}
// put near your update logic
float B = 122;
float T = 1.0f; // wall half-thickness
float H = 4.0f; // wall height
BoundingBox walls[4] = {
// left (x = -B)
{ (Vector3){-B - T, 0.0f, -B - T}, (Vector3){-B + T, H, B + T} },
// right (x = +B)
{ (Vector3){ B - T, 0.0f, -B - T}, (Vector3){ B + T, H, B + T} },
// bottom (z = -B)
{ (Vector3){-B - T, 0.0f, -B - T}, (Vector3){ B + T, H, -B + T} },
// top (z = +B)
{ (Vector3){-B - T, 0.0f, B - T}, (Vector3){ B + T, H, B + T} },
};
for (int i = 0; i < 4; ++i) ResolveAgainstBoxXZ(&g, walls[i]);
// (Optional) debug draw inside BeginMode3D/EndMode3D:
for (int i = 0; i < 4; ++i) DrawBoundingBox(walls[i], RED);
float delta = GetFrameTime();
g.player.headLerp = Lerp(g.player.headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0f*delta);
g.player.camera.position = (Vector3){
@@ -341,18 +475,37 @@ int main(void)
g.player.lean.x = Lerp(g.player.lean.x, sideway*0.02f, 10.0f*delta);
g.player.lean.y = Lerp(g.player.lean.y, forward*0.015f, 10.0f*delta);
bbPos.x += (g.player.position.x - bbPos.x)*.005;
bbPos.z += (g.player.position.z - bbPos.z)*.005;
// wall editor
if (IsKeyDown(KEY_RIGHT) && IsKeyDown(KEY_LEFT_SHIFT)) acorn_position.x += 0.5f;
else if (IsKeyPressed(KEY_RIGHT)) acorn_position.x += 0.5f;
if (IsKeyDown(KEY_LEFT) && IsKeyDown(KEY_LEFT_SHIFT)) acorn_position.x -= 0.5f;
else if (IsKeyPressed(KEY_LEFT)) acorn_position.x -= 0.5f;
if (IsKeyDown(KEY_UP) && IsKeyDown(KEY_LEFT_SHIFT)) acorn_position.z += 0.5f;
else if (IsKeyPressed(KEY_UP)) acorn_position.z += 0.5f;
if (IsKeyDown(KEY_DOWN) && IsKeyDown(KEY_LEFT_SHIFT)) acorn_position.z -= 0.5f;
else if (IsKeyPressed(KEY_DOWN)) acorn_position.z -= 0.5f;
float rotSpeed = 45.0f * GetFrameTime(); // deg/sec
if (IsKeyDown(KEY_Q)) wall_yaw -= rotSpeed;
if (IsKeyDown(KEY_E)) wall_yaw += rotSpeed;
//
UpdateMusicStream(g.bgm);
UpdateCameraAngle(&g);
/*
int bbdifx = g.player.position.x - bbPos.x;
int bbdifz = g.player.position.z - bbPos.z;
bbPos.x += 0.01 * bbdifx;
bbPos.z += 0.01 * bbdifz;
*/
break;
};
}
@@ -376,6 +529,15 @@ int main(void)
{
ClearBackground(BLACK);
Vector3 camPos = g.player.camera.position;
Vector3 camFwd = Vector3Normalize(Vector3Subtract(g.player.camera.target, camPos));
// Camera forward (normalize target - position)
Vector3 forward = Vector3Normalize(Vector3Subtract(g.player.camera.target, g.player.camera.position));
SetShaderValue(fog, locPlayer, &camPos, SHADER_UNIFORM_VEC3);
SetShaderValue(fog, locSpotDir, &camFwd, SHADER_UNIFORM_VEC3);
BeginMode3D(g.player.camera);
rlDisableBackfaceCulling();
@@ -395,23 +557,50 @@ int main(void)
DrawLevel(mdlTile);
BeginShaderMode(shAlphaClip);
{
// --- Trees use same fog shader but with alpha-cut enabled ---
SetShaderValue(fog, locCutoff_fog, &cutoffAlpha, SHADER_UNIFORM_FLOAT);
BeginShaderMode(fog);
//DrawModel(wall, wall_position, 5.0, WHITE);
DrawModelEx(acorn, acorn_position, (Vector3){0,1,0}, wall_yaw, (Vector3){0.25,0.25,0.25}, WHITE);
RenderTrees(&g, tree, treepos, treeSize);
}
//DrawBillboard(g.player.camera, sign, bbPos, bbSize, WHITE); //zombie
DrawPerimeter(wall, 122.0f, 1.5f);
EndShaderMode();
//DrawBillboard(g.player.camera, sign, bbPos, bbSize, WHITE); //This was the texture chasing you.
// Restore opaque cutoff for anything else you draw with that material later
SetShaderValue(fog, locCutoff_fog, &cutoffOpaque, SHADER_UNIFORM_FLOAT);
EndMode3D();
// Draw info box
DrawRectangle(5, 5, 330, 75, Fade(SKYBLUE, 0.5f));
DrawRectangleLines(5, 5, 330, 75, BLUE);
if(g.isJumpscared == 1 | g.isJumpscared == 2)
{
DrawTextureEx(sign, (Vector2){700, 300}, /*rotation*/0.0f, /*scale*/50.0f, WHITE);
}
DrawText("Camera controls:", 15, 15, 10, BLACK);
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, BLACK);
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, BLACK);
DrawText(TextFormat("- Velocity Len: (%06.3f)", Vector2Length((Vector2){ g.player.velocity.x, g.player.velocity.z })), 15, 60, 10, BLACK);
// Draw info box
DrawRectangle(5, 5, 330*1.5, 75*1.25, Fade(SKYBLUE, 0.5f));
DrawRectangleLines(5, 5, 330*1.5, 75*1.25, BLUE);
DrawText("Camera controls:", 15, 15, 20, BLACK);
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 20, BLACK);
DrawText("- Look around: arrow keys or mouse", 15, 45, 20, BLACK);
DrawText(TextFormat("- Velocity Len: (%06.3f)", Vector2Length((Vector2){ g.player.velocity.x, g.player.velocity.z })), 15, 60, 20, BLACK);
DrawText(
TextFormat("x: (%06.3f), y: (%06.3f), z: (%06.3f)", acorn_position.x, acorn_position.y, acorn_position.z),
15, 75, 20, BLACK
);
if (g.nearAcorn == 1)
{
int acorn_text_width = MeasureText("Press E to Collect the Acorn", 50);
DrawText("Press E to Collect the Acorn", (screenWidth - acorn_text_width)/2, screenHeight * 0.8, 50, PURPLE);
}
break;
}
@@ -419,8 +608,8 @@ int main(void)
EndDrawing();
//----------------------------------------------------------------------------------
};
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// De-Initialization
//--------------------------------------------------------------------------------------
// Detach the texture from the model so UnloadModel won't try to free it.
@@ -429,8 +618,15 @@ int main(void)
// Now free resources you loaded:
UnloadModel(mdlTile); // frees the model and its mesh/VBOs
UnloadTexture(texGrass); // frees the grass texture you loaded
UnloadTexture(sign); // frees billboard texture
UnloadTexture(tree); // frees tree texture
UnloadTexture(sign);
UnloadModel(wall);
UnloadModel(acorn);
UnloadSound(g.jumpScare);
StopMusicStream(g.bgm);
UnloadMusicStream(g.bgm);
CloseAudioDevice();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
@@ -687,12 +883,12 @@ static inline void DrawTreeBillboardStable(Camera cam, Texture2D tex, Vector3 gr
static void RenderTrees(Master* g, Texture2D tree, Vector3 baseTreePos, float treeSize)
{
const int floorExtent = FLOOR_EXTENT;
const int floorExtent = FLOOR_EXTENT - 3;
const float tileSize = TILE_SIZE;
// Placement knobs
const int densityA = 10; // 1-in-10 on (odd,odd)
const int densityB = 20; // 1-in-14 on (even,even)
const int densityB = 13; // 1-in-14 on (even,even)
const float jitter = tileSize * 0.35f; // random in-tile offset
const float groundY = baseTreePos.y; // <-- use this as terrain height
@@ -723,3 +919,216 @@ static void RenderTrees(Master* g, Texture2D tree, Vector3 baseTreePos, float tr
}
}
}
static void ApplyFogShaderToModel(Model *m, Shader fog)
{
// 1) Tell raylib which uniform in your shader is the ALBEDO map
fog.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(fog, "matModel");
fog.locs[SHADER_LOC_MATRIX_VIEW] = GetShaderLocation(fog, "matView");
fog.locs[SHADER_LOC_MATRIX_PROJECTION] = GetShaderLocation(fog, "matProjection");
fog.locs[SHADER_LOC_MAP_ALBEDO] = GetShaderLocation(fog, "texture0"); // your FS: uniform sampler2D texture0;
// (optional but nice)
fog.locs[SHADER_LOC_COLOR_DIFFUSE] = GetShaderLocation(fog, "colDiffuse");
// 2) For each material, make sure the base color texture ends up in the ALBEDO slot
for (int i = 0; i < m->materialCount; ++i) {
Material *mat = &m->materials[i];
// Some importers put the base map in DIFFUSE, copy to ALBEDO if ALBEDO is empty.
if (mat->maps[MATERIAL_MAP_ALBEDO].texture.id == 0 &&
mat->maps[MATERIAL_MAP_DIFFUSE].texture.id != 0) {
mat->maps[MATERIAL_MAP_ALBEDO].texture = mat->maps[MATERIAL_MAP_DIFFUSE].texture;
}
// Ensure non-zero tint
if (mat->maps[MATERIAL_MAP_ALBEDO].color.a == 0) mat->maps[MATERIAL_MAP_ALBEDO].color = WHITE;
// 3) Attach your fog shader to this material
mat->shader = fog;
}
}
// Build player's AABB from its position (XZ radius, fixed height)
static BoundingBox PlayerAABB(Vector3 p)
{
BoundingBox bb;
bb.min = (Vector3){ p.x - PLAYER_RADIUS, p.y, p.z - PLAYER_RADIUS };
bb.max = (Vector3){ p.x + PLAYER_RADIUS, p.y + PLAYER_HEIGHT, p.z + PLAYER_RADIUS };
return bb;
}
// Combine all mesh AABBs of a Model in LOCAL space
static BoundingBox ModelLocalAABB(Model m)
{
BoundingBox out;
out.min = (Vector3){ FLT_MAX, FLT_MAX, FLT_MAX };
out.max = (Vector3){ -FLT_MAX, -FLT_MAX, -FLT_MAX };
for (int i = 0; i < m.meshCount; ++i) {
BoundingBox b = GetMeshBoundingBox(m.meshes[i]); // local-space box of this mesh
if (b.min.x < out.min.x) out.min.x = b.min.x;
if (b.min.y < out.min.y) out.min.y = b.min.y;
if (b.min.z < out.min.z) out.min.z = b.min.z;
if (b.max.x > out.max.x) out.max.x = b.max.x;
if (b.max.y > out.max.y) out.max.y = b.max.y;
if (b.max.z > out.max.z) out.max.z = b.max.z;
}
return out;
}
// Transform a BoundingBox by a matrix and return its world AABB
static BoundingBox TransformAABB(BoundingBox bb, Matrix M)
{
Vector3 c[8] = {
{bb.min.x, bb.min.y, bb.min.z}, {bb.max.x, bb.min.y, bb.min.z},
{bb.min.x, bb.max.y, bb.min.z}, {bb.max.x, bb.max.y, bb.min.z},
{bb.min.x, bb.min.y, bb.max.z}, {bb.max.x, bb.min.y, bb.max.z},
{bb.min.x, bb.max.y, bb.max.z}, {bb.max.x, bb.max.y, bb.max.z},
};
BoundingBox out;
out.min = (Vector3){ FLT_MAX, FLT_MAX, FLT_MAX };
out.max = (Vector3){ -FLT_MAX, -FLT_MAX, -FLT_MAX };
for (int i = 0; i < 8; ++i) {
Vector3 t = Vector3Transform(c[i], M);
if (t.x < out.min.x) out.min.x = t.x;
if (t.y < out.min.y) out.min.y = t.y;
if (t.z < out.min.z) out.min.z = t.z;
if (t.x > out.max.x) out.max.x = t.x;
if (t.y > out.max.y) out.max.y = t.y;
if (t.z > out.max.z) out.max.z = t.z;
}
return out;
}
// Build world AABB for a model using the same T*R*S you render with
static BoundingBox MakeModelWorldAABB(Model m, Vector3 pos, Vector3 scale, float yawDeg)
{
Matrix S = MatrixScale(scale.x, scale.y, scale.z);
Matrix R = MatrixRotateY(DEG2RAD * yawDeg);
Matrix T = MatrixTranslate(pos.x, pos.y, pos.z);
Matrix SRT = MatrixMultiply(MatrixMultiply(S, R), T); // S * R * T
Matrix M = MatrixMultiply(m.transform, SRT); // model.transform * SRT
BoundingBox out = { .min = { FLT_MAX, FLT_MAX, FLT_MAX },
.max = { -FLT_MAX, -FLT_MAX, -FLT_MAX } };
for (int i = 0; i < m.meshCount; ++i) {
BoundingBox local = GetMeshBoundingBox(m.meshes[i]);
BoundingBox world = TransformAABB(local, M);
if (world.min.x < out.min.x) out.min.x = world.min.x;
if (world.min.y < out.min.y) out.min.y = world.min.y;
if (world.min.z < out.min.z) out.min.z = world.min.z;
if (world.max.x > out.max.x) out.max.x = world.max.x;
if (world.max.y > out.max.y) out.max.y = world.max.y;
if (world.max.z > out.max.z) out.max.z = world.max.z;
}
return out;
}
// Push player out of a box on the smallest X/Z overlap (slide) and zero that velocity axis
static void ResolveAgainstBoxXZ(Master* g, BoundingBox box)
{
BoundingBox p = PlayerAABB(g->player.position);
// Quick reject
if (!CheckCollisionBoxes(p, box)) return;
// Overlaps on X and Z
float ox = fminf(p.max.x, box.max.x) - fmaxf(p.min.x, box.min.x);
float oz = fminf(p.max.z, box.max.z) - fmaxf(p.min.z, box.min.z);
if (ox <= 0 || oz <= 0) return;
// Centers to know which way to push
float cxp = 0.5f * (p.min.x + p.max.x);
float czp = 0.5f * (p.min.z + p.max.z);
float cxb = 0.5f * (box.min.x + box.max.x);
float czb = 0.5f * (box.min.z + box.max.z);
// Resolve along the smallest axis
if (ox < oz) {
float push = (cxp < cxb) ? -ox : ox;
g->player.position.x += push;
g->player.velocity.x = 0.0f;
} else {
float push = (czp < czb) ? -oz : oz;
g->player.position.z += push;
g->player.velocity.z = 0.0f;
}
}
// Length of the model along local X (used to tile segments cleanly)
static float ModelLengthXUnits(Model m) {
BoundingBox bb = ModelLocalAABB(m); // you already have this helper
return (bb.max.x - bb.min.x);
}
static float ModelLengthZUnits(Model m) {
BoundingBox bb = ModelLocalAABB(m);
return (bb.max.z - bb.min.z);
}
// Draw repeated wall segments around the perimeter (z=±border, x=±border)
static void DrawPerimeter(Model wall, float border, float scale) {
const float HALF = FLOOR_EXTENT * TILE_SIZE; // e.g. 25*5 = 125
Vector3 scl = { scale, scale, scale };
//float segLen = ModelLengthXUnits(wall) * scale;
float segLen = ModelLengthZUnits(wall) * scale;
if (segLen <= 0.001f) segLen = TILE_SIZE; // safety fallback
int count = (int)ceilf((2.0f * HALF) / segLen) + 1;
scl.x += 0.1;
scl.y += 0.1;
scl.z += 0.1;
// Top & bottom edges: fence runs along +X (yaw 0/180)
for (int i = 0; i < count; ++i) {
float x = -HALF + i * segLen;
DrawModelEx(wall, (Vector3){ x, 0.0f, border }, (Vector3){0,1,0}, 90.0f, scl, WHITE);
DrawModelEx(wall, (Vector3){ x, 0.0f, -border }, (Vector3){0,1,0}, 270.0f, scl, WHITE);
}
// Left & right edges: rotate 90° so fence runs along Z
for (int i = 0; i < count; ++i) {
float z = -HALF + i * segLen;
DrawModelEx(wall, (Vector3){ border, 0.0f, z }, (Vector3){0,1,0}, 0.0f, scl, WHITE);
DrawModelEx(wall, (Vector3){ -border, 0.0f, z }, (Vector3){0,1,0}, 180.0f, scl, WHITE);
}
}
// Optional: collide player with the same perimeter using your AABB helpers
static void CollidePerimeter(Master* g, Model wall, float border, float scale) {
const float HALF = FLOOR_EXTENT * TILE_SIZE;
const Vector3 scl = { scale, scale, scale };
float segLen = ModelLengthXUnits(wall) * scale;
if (segLen <= 0.001f) segLen = TILE_SIZE;
int count = (int)ceilf((2.0f * HALF) / segLen) + 1;
for (int i = 0; i < count; ++i) {
float x = -HALF + i * segLen;
ResolveAgainstBoxXZ(g, MakeModelWorldAABB(wall, (Vector3){ x, 0.0f, border }, scl, 0.0f));
ResolveAgainstBoxXZ(g, MakeModelWorldAABB(wall, (Vector3){ x, 0.0f, -border }, scl, 180.0f));
}
for (int i = 0; i < count; ++i) {
float z = -HALF + i * segLen;
ResolveAgainstBoxXZ(g, MakeModelWorldAABB(wall, (Vector3){ border, 0.0f, z }, scl, 90.0f));
ResolveAgainstBoxXZ(g, MakeModelWorldAABB(wall, (Vector3){ -border, 0.0f, z }, scl, 90.0f));
}
}
float square(float num)
{
float out = num * num;
return out;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Some files were not shown because too many files have changed in this diff Show More