Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## About

Fork of the discontinued [GameplayFootball](https://github.com/BazkieBumpercar/GameplayFootball) C++ football game. The goal is to modernize and keep it building on Linux, macOS, and Windows. The `google_brain` branch contains Google Brain's RL-focused variant as a reference.

## Build

**Prerequisites (Linux):**
```bash
sudo apt-get install git cmake build-essential libgl1-mesa-dev libsdl2-dev \
libsdl2-image-dev libsdl2-ttf-dev libsdl2-gfx-dev libopenal-dev libboost-all-dev \
libdirectfb-dev libst-dev mesa-utils xvfb x11vnc libsqlite3-dev
```

**Prerequisites (macOS):**
```bash
brew install cmake sdl2 sdl2_image sdl2_ttf sdl2_gfx boost openal-soft
```

**Build steps (Linux/macOS):**
```bash
cp -R data/. build
cd build
cmake ..
make -j$(nproc)
./gameplayfootball
```

> macOS note: the game compiles but does not run yet — rendering must happen on the main thread.

**Debug build:**
```bash
cd build && cmake -DCMAKE_BUILD_TYPE=Debug .. && make -j$(nproc)
```

There is no test suite. Validation is done by running the game.

## Architecture

The engine ("Blunted2") is a component/entity system split into static libraries linked into the `gameplayfootball` executable. `CMakeLists.txt` + `sources.cmake` define the library structure.

**Engine libraries (`blunted2` aggregate):**

| Library | Path | Role |
|---|---|---|
| `baselib` | `src/base/` | Math, geometry, logging, properties |
| `frameworklib` | `src/framework/` | Task scheduling, worker threads |
| `scenelib` | `src/scene/` | Scene graph (2D/3D), scene objects/resources |
| `systemsgraphicslib` | `src/systems/graphics/` | OpenGL renderer, graphics objects/tasks |
| `systemsaudiolib` | `src/systems/audio/` | OpenAL audio |
| `managerslib` | `src/managers/` | Resource managers |
| `utilslib` / `gui2lib` | `src/utils/` | Utilities, GUI widgets |
| `loaderslib` | `src/loaders/` | Asset loading |
| `typeslib` | `src/types/` | Shared type definitions |

**Game libraries (link against `blunted2`):**

| Library | Path | Role |
|---|---|---|
| `gamelib` | `src/onthepitch/` | Match simulation: ball, players, AI, teams, referee |
| `hidlib` | `src/hid/` | Human input device handling |
| `menulib` | `src/menu/` | Game menus |
| `datalib` | `src/data/` | Data loading (configs, databases) |
| `leaguelib` | `src/league/` | League/tournament logic |

**Entry point:** `src/main.cpp` → `src/blunted.cpp` (`Blunted` class) → `src/gametask.cpp` (`GameTask`).

**Rendering:** `src/systems/graphics/rendering/opengl_renderer3d.cpp` implements `IRenderer3D`. Shaders live in `data/media/shaders/` (GLSL: `ambient.frag`, `lighting.frag`, `postprocess.frag`, `simple.frag`). The renderer is driven by `GraphicsSystem` / `GraphicsTask` via the scheduler in `src/systems/graphics/scheduler.cpp`.

**Game data:** `data/` must be copied into `build/` before running (CMake does not do this automatically). Databases are SQLite files under `data/databases/`.
11 changes: 9 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ include_directories(${SDL2_TTF_DIRS})
FIND_PACKAGE(SDL2_gfx REQUIRED)
include_directories(${SDL2_GFX_DIRS})

FIND_PACKAGE(Boost REQUIRED COMPONENTS system thread filesystem)
FIND_PACKAGE(Boost REQUIRED COMPONENTS thread filesystem)
include_directories(${Boost_INCLUDE_DIR})

FIND_PACKAGE(OpenAL REQUIRED)
Expand Down Expand Up @@ -98,9 +98,16 @@ add_library(menulib ${MENU_SOURCES} ${MENU_HEADERS})
add_library(datalib ${DATA_SOURCES} ${DATA_HEADERS})

set(LIBRARIES gamelib hidlib menulib datalib leaguelib blunted2
Boost::filesystem Boost::system Boost::thread SQLite::SQLite3
Boost::filesystem Boost::thread SQLite::SQLite3
${SDL2_IMAGE_LIBRARIES} ${SDL2_TTF_LIBRARIES} ${SDL2_GFX_LIBRARIES}
${SDL2_LIBRARIES} ${OPENAL_LIBRARY} dl m ${OPENGL_LIBRARIES})

add_executable(gameplayfootball WIN32 ${CORE_SOURCES} ${CORE_HEADERS})
target_link_libraries(gameplayfootball ${LIBRARIES})

if(APPLE)
set_target_properties(gameplayfootball PROPERTIES
BUILD_RPATH "/Library/Frameworks;/opt/homebrew/lib"
INSTALL_RPATH "/Library/Frameworks;/opt/homebrew/lib"
)
endif()
14 changes: 7 additions & 7 deletions data/media/shaders/ambient.frag
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ float GetEdge(vec2 pos) {
float depths[9];
vec3 normals[9];
for (int i = 0; i < 9; i++) {
float depth = texture2D(map_depth, pos + offsets[i] * 0.001).x;
float depth = texture(map_depth, pos + offsets[i] * 0.001).x;
depths[i] = cameraClip.y / (depth - cameraClip.x);
normals[i] = texture2D(map_normal, pos + offsets[i] * 0.001).xyz;
normals[i] = texture(map_normal, pos + offsets[i] * 0.001).xyz;
}

vec4 deltas1;
Expand Down Expand Up @@ -117,11 +117,11 @@ void main(void) {
texCoord.x /= contextWidth;
texCoord.y /= contextHeight;

float depth = texture2D(map_depth, texCoord).x;
float depth = texture(map_depth, texCoord).x;

vec3 worldPosition = GetWorldPosition(texCoord, depth);

vec3 base = texture2D(map_albedo, texCoord).xyz;
vec3 base = texture(map_albedo, texCoord).xyz;

float brightness = 0.15f;//0.25f;

Expand All @@ -137,13 +137,13 @@ void main(void) {
vec2 noiseScale = vec2(contextWidth / 4.0f, contextHeight / 4.0f);
float SSAO_radius = 0.18f;//0.12f;

vec3 normal = texture2D(map_normal, texCoord).xyz;
vec3 normal = texture(map_normal, texCoord).xyz;
float SSAO = 0.0;

vec3 viewPosition = vec3(viewMatrix * vec4(worldPosition, 1.0f));
vec3 viewNormal = vec3(viewMatrix * vec4(normal, 0.0f));

vec3 randomVec = -texture2D(map_noise, texCoord * noiseScale).xyz * 2.0f - 1.0f;
vec3 randomVec = -texture(map_noise, texCoord * noiseScale).xyz * 2.0f - 1.0f;
vec3 tangent = normalize(randomVec - viewNormal * dot(randomVec, viewNormal));
vec3 bitangent = cross(viewNormal, tangent);
mat3 tbn = mat3(tangent, bitangent, viewNormal);
Expand Down Expand Up @@ -184,7 +184,7 @@ void main(void) {

// self-illumination

vec4 aux = texture2D(map_aux, texCoord.st);
vec4 aux = texture(map_aux, texCoord.st);
float self_illumination = aux.w;

vec3 fragColor = vec3(clamp(base * (1.0 + self_illumination), 0.0, 1.0));
Expand Down
8 changes: 4 additions & 4 deletions data/media/shaders/lighting.frag
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void main(void) {
texCoord.x /= contextWidth;
texCoord.y /= contextHeight;

float depth = texture2D(map_depth, texCoord).x; // non-linear (0 .. 1)
float depth = texture(map_depth, texCoord).x; // non-linear (0 .. 1)

vec3 worldPosition = GetWorldPosition(texCoord, depth);

Expand All @@ -57,7 +57,7 @@ void main(void) {

vec3 lightDir = normalize(lightPosition - worldPosition.xyz);

vec4 normalshine = texture2D(map_normal, texCoord);
vec4 normalshine = texture(map_normal, texCoord);
vec3 normal = normalize(normalshine.xyz);

float nDotLD = dot(lightDir, normal);
Expand Down Expand Up @@ -92,7 +92,7 @@ void main(void) {
vec3 eyeToFrag = worldPosition.xyz - cameraPosition;
vec3 refl = reflect(normalize(eyeToFrag), normal);

vec4 base = texture2D(map_albedo, texCoord);
vec4 base = texture(map_albedo, texCoord);

float spec = base.w;
vec3 specularColor = lightColor;// * 0.2f + base.rgb * 0.8f;
Expand Down Expand Up @@ -127,7 +127,7 @@ void main(void) {
}

// nice debug
//shaded = pow(texture2D(map_depth, texCoord * 1.1f + vec2(0.05, 0.05)).r, 3.0f) * 3.0f - 0.6f;
//shaded = pow(texture(map_depth, texCoord * 1.1f + vec2(0.05, 0.05)).r, 3.0f) * 3.0f - 0.6f;

// how 'seriously' do we take shadows? various options below
//shaded *= 0.25;
Expand Down
16 changes: 8 additions & 8 deletions data/media/shaders/postprocess.frag
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,18 @@ void main(void) {
texCoord.x /= contextWidth;
texCoord.y /= contextHeight;

vec4 accum = texture2D(map_accumulation, texCoord);
vec4 accum = texture(map_accumulation, texCoord);
vec3 base = accum.rgb;

vec4 modifier = texture2D(map_modifier, texCoord);
vec4 modifier = texture(map_modifier, texCoord);

// edge blur
if (modifier.r > 0.0) {
vec3 smoothPixel = vec3(0);
smoothPixel += texture2D(map_accumulation, texCoord + vec2(0, 1 / contextHeight)).xyz;
smoothPixel += texture2D(map_accumulation, texCoord + vec2(1 / contextWidth, 0)).xyz;
smoothPixel += texture2D(map_accumulation, texCoord + vec2(0, -1 / contextHeight)).xyz;
smoothPixel += texture2D(map_accumulation, texCoord + vec2(-1 / contextWidth, 0)).xyz;
smoothPixel += texture(map_accumulation, texCoord + vec2(0, 1 / contextHeight)).xyz;
smoothPixel += texture(map_accumulation, texCoord + vec2(1 / contextWidth, 0)).xyz;
smoothPixel += texture(map_accumulation, texCoord + vec2(0, -1 / contextHeight)).xyz;
smoothPixel += texture(map_accumulation, texCoord + vec2(-1 / contextWidth, 0)).xyz;
smoothPixel *= 0.25;
base = base * (1.0 - modifier.r) + smoothPixel * modifier.r;
//base = base * (1.0 - modifier.r) + vec3(0, 0, 0) * modifier.r * 0.5 + smoothPixel * modifier.r * 0.5; // cartooney effect
Expand All @@ -82,7 +82,7 @@ void main(void) {

int SSAO_blurSize = 4;

float SSAO = 0.0f; // texture2D(map_modifier, texCoord).g;
float SSAO = 0.0f; // texture(map_modifier, texCoord).g;

vec2 texelSize = 1.0f / vec2(textureSize(map_modifier, 0));
vec2 hlim = vec2(float(-SSAO_blurSize) * 0.5f + 0.5f);
Expand All @@ -101,7 +101,7 @@ void main(void) {

// fog

float depth = texture2D(map_depth, texCoord).x;
float depth = texture(map_depth, texCoord).x;

// convert from non-linear to linear
float fragDepth = cameraClip.y / (depth - cameraClip.x);
Expand Down
8 changes: 4 additions & 4 deletions data/media/shaders/simple.frag
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@ out vec4 stdout2;

void main(void) {

vec4 base = texture2D(map_albedo, frag_texcoord.st);
vec4 base = texture(map_albedo, frag_texcoord.st);
if (base.a < 0.12) discard;
vec3 bump;
if (materialbools.x == 1.0f) {
bump = normalize(texture2D(map_normal, frag_texcoord.st).xyz * 2.0 - 1.0);
bump = normalize(texture(map_normal, frag_texcoord.st).xyz * 2.0 - 1.0);
} else {
bump = vec3(0, 0, 1);
}
float spec;
if (materialbools.y == 1.0f) {
spec = texture2D(map_specular, frag_texcoord.st).x * materialparams.y;
spec = texture(map_specular, frag_texcoord.st).x * materialparams.y;
} else {
spec = materialparams.y;
}
float illumination;
if (materialbools.z == 1.0f) {
illumination = texture2D(map_illumination, frag_texcoord.st).x;
illumination = texture(map_illumination, frag_texcoord.st).x;
} else {
illumination = materialparams.z;
}
Expand Down
Loading