#include #include #include "engineAssets.h" #include "floor.h" static void BindWaterTexture(Shader shader, const char *uniformName, Texture2D texture, int slot) { int loc = GetShaderLocation(shader, uniformName); if (loc < 0) return; rlActiveTextureSlot(slot); rlEnableTexture(texture.id); SetShaderValue(shader, loc, &slot, SHADER_UNIFORM_INT); } static void PrepareTiledTexture(Texture2D texture) { SetTextureWrap(texture, TEXTURE_WRAP_REPEAT); GenTextureMipmaps(&texture); SetTextureFilter(texture, TEXTURE_FILTER_TRILINEAR); } static Texture2D CreateDepthGradientTexture(void) { Image gradientImage = GenImageGradientLinear(64, 64, 90, (Color){12, 44, 84, 255}, (Color){64, 168, 186, 255}); Texture2D depthGradient = LoadTextureFromImage(gradientImage); UnloadImage(gradientImage); SetTextureWrap(depthGradient, TEXTURE_WRAP_CLAMP); return depthGradient; } static void ConfigureFloorShaderUniforms(Shader shader, Texture2D base, float worldTileSize, float textureSize) { float aspect = (float)GetScreenHeight() / (float)GetScreenWidth(); float pixelization = 2048.0f; float noiseCoordinateScale = worldTileSize * ((float)base.width / textureSize); int aspectLoc = GetShaderLocation(shader, "aspectRatio"); int pixelLoc = GetShaderLocation(shader, "pixelization"); int noiseCoordinateScaleLoc = GetShaderLocation(shader, "noiseCoordinateScale"); SetShaderValue(shader, aspectLoc, &aspect, SHADER_UNIFORM_FLOAT); SetShaderValue(shader, pixelLoc, &pixelization, SHADER_UNIFORM_FLOAT); SetShaderValue(shader, noiseCoordinateScaleLoc, &noiseCoordinateScale, SHADER_UNIFORM_FLOAT); } Floor CreateFloor(void) { Texture2D base = LoadTextureCached("assets/water_base.png"); Texture2D caustic = LoadTextureCached("assets/water_caustics.png"); Texture2D causticHighlight = LoadTextureCached("assets/water_caustics_highlights.png"); Texture2D noise = LoadTextureCached("assets/water_noise.png"); Texture2D cloud = LoadTextureCached("assets/water_cloudnoise.png"); Texture2D voronoise = LoadTextureCached("assets/water_voronoise.png"); PrepareTiledTexture(caustic); PrepareTiledTexture(causticHighlight); PrepareTiledTexture(noise); PrepareTiledTexture(cloud); PrepareTiledTexture(voronoise); Texture2D depthGradient = CreateDepthGradientTexture(); float textureWidth = 64.0f; Floor floor = {.sprite = {.texture = base, .frameSize = {textureWidth, textureWidth}, .sourceRec = {0.0f, 0.0f, textureWidth, textureWidth}, .destRec = {0.0f, 0.0f, textureWidth, textureWidth}, .origin = {textureWidth / 2, textureWidth / 2}, .rotation = 0.0f, .color = WHITE}, .bounds = {0}, .shader = LoadShader("shaders/water.vs", "shaders/water.fs"), .time = 0.0f}; float worldTileSize = 128.0f; float textureSize = 32.0f; floor.sprite.frameSize = (Vector2){worldTileSize, worldTileSize}; floor.sprite.sourceRec = (Rectangle){0, 0, textureSize, textureSize}; floor.sprite.destRec = (Rectangle){0, 0, worldTileSize, worldTileSize}; floor.sprite.origin = (Vector2){0, 0}; ConfigureFloorShaderUniforms(floor.shader, base, worldTileSize, textureSize); floor.sprite.texture = base; floor.causticTexture = caustic; floor.causticHighlightTexture = causticHighlight; floor.noiseTexture = noise; floor.cloudTexture = cloud; floor.voronoiseTexture = voronoise; floor.depthGradientTexture = depthGradient; return floor; } void UpdateFloor(Floor *floor, Camera2D *camera) { floor->bounds.x = (int)((camera->target.x - (GetScreenWidth() / 2.0f / camera->zoom)) / floor->sprite.frameSize.x) - 1; floor->bounds.width = (int)((camera->target.x + (GetScreenWidth() / 2.0f / camera->zoom)) / floor->sprite.frameSize.x) + 1; floor->bounds.y = (int)((camera->target.y - (GetScreenHeight() / 2.0f / camera->zoom)) / floor->sprite.frameSize.y) - 1; floor->bounds.height = (int)((camera->target.y + (GetScreenHeight() / 2.0f / camera->zoom)) / floor->sprite.frameSize.y) + 1; floor->time += GetFrameTime(); int timeLoc = GetShaderLocation(floor->shader, "time"); SetShaderValue(floor->shader, timeLoc, &floor->time, SHADER_UNIFORM_FLOAT); } void RenderFloor(Floor *floor) { BeginShaderMode(floor->shader); BindWaterTexture(floor->shader, "causticTexture", floor->causticTexture, 1); BindWaterTexture(floor->shader, "causticHighlightTexture", floor->causticHighlightTexture, 2); BindWaterTexture(floor->shader, "causticNoiseTexture", floor->noiseTexture, 3); BindWaterTexture(floor->shader, "causticFadeNoiseTexture", floor->cloudTexture, 4); BindWaterTexture(floor->shader, "specularNoiseTexture", floor->voronoiseTexture, 5); BindWaterTexture(floor->shader, "specularMovementLeftNoiseTexture", floor->voronoiseTexture, 6); BindWaterTexture(floor->shader, "specularMovementRightNoiseTexture", floor->cloudTexture, 7); BindWaterTexture(floor->shader, "foamTexture", floor->voronoiseTexture, 8); BindWaterTexture(floor->shader, "waterDepthGradient", floor->depthGradientTexture, 9); for (int y = (int)floor->bounds.y; y <= (int)floor->bounds.height; y++) { for (int x = (int)floor->bounds.x; x <= (int)floor->bounds.width; x++) { Vector2 floorPosition = {x * floor->sprite.frameSize.x, y * floor->sprite.frameSize.y}; UpdateSpriteDestRec(&floor->sprite, &floorPosition); RenderSprite(&floor->sprite); } } EndShaderMode(); } void UnloadFloor(Floor *floor) { UnloadShader(floor->shader); UnloadTexture(floor->depthGradientTexture); }