diff --git a/cmake/create-project/CMakeLists.txt b/examples/empty-project/CMakeLists.txt
similarity index 100%
rename from cmake/create-project/CMakeLists.txt
rename to examples/empty-project/CMakeLists.txt
diff --git a/cmake/create-project/src/main.cpp b/examples/empty-project/src/main.cpp
similarity index 100%
rename from cmake/create-project/src/main.cpp
rename to examples/empty-project/src/main.cpp
diff --git a/examples/sample-scenes/.idea/.gitignore b/examples/sample-scenes/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/examples/sample-scenes/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/examples/sample-scenes/.idea/.name b/examples/sample-scenes/.idea/.name
new file mode 100644
index 0000000..da9b741
--- /dev/null
+++ b/examples/sample-scenes/.idea/.name
@@ -0,0 +1 @@
+WeirdSamples
\ No newline at end of file
diff --git a/examples/sample-scenes/.idea/editor.xml b/examples/sample-scenes/.idea/editor.xml
new file mode 100644
index 0000000..ead1d8a
--- /dev/null
+++ b/examples/sample-scenes/.idea/editor.xml
@@ -0,0 +1,248 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/sample-scenes/.idea/misc.xml b/examples/sample-scenes/.idea/misc.xml
new file mode 100644
index 0000000..0b76fe5
--- /dev/null
+++ b/examples/sample-scenes/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/sample-scenes/.idea/modules.xml b/examples/sample-scenes/.idea/modules.xml
new file mode 100644
index 0000000..4e17cb7
--- /dev/null
+++ b/examples/sample-scenes/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/sample-scenes/.idea/sample-scenes.iml b/examples/sample-scenes/.idea/sample-scenes.iml
new file mode 100644
index 0000000..f08604b
--- /dev/null
+++ b/examples/sample-scenes/.idea/sample-scenes.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/examples/sample-scenes/.idea/vcs.xml b/examples/sample-scenes/.idea/vcs.xml
new file mode 100644
index 0000000..415e336
--- /dev/null
+++ b/examples/sample-scenes/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/sample-scenes/CMakeLists.txt b/examples/sample-scenes/CMakeLists.txt
new file mode 100644
index 0000000..47267c5
--- /dev/null
+++ b/examples/sample-scenes/CMakeLists.txt
@@ -0,0 +1,101 @@
+cmake_minimum_required(VERSION 3.10)
+project(WeirdSamples)
+
+# Create folders if they don't exist
+file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/assets")
+file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/include")
+file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/src")
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+# Option to switch between local and online version of WeirdEngine
+option(USE_LOCAL_WEIRD_ENGINE "Use local version of WeirdEngine" ON)
+
+# Set paths for the local WeirdEngine
+set(WEIRD_ENGINE_LOCAL_PATH "../../")
+
+if(USE_LOCAL_WEIRD_ENGINE)
+ # Use the local version of WeirdEngine
+ message(STATUS "Using local version of WeirdEngine")
+ add_subdirectory(${WEIRD_ENGINE_LOCAL_PATH} ${CMAKE_BINARY_DIR}/weird-engine)
+else()
+ # Fetch WeirdEngine from GitHub
+ message(STATUS "Using online version of WeirdEngine")
+ include(FetchContent)
+ FetchContent_Declare(
+ WeirdEngine
+ GIT_REPOSITORY https://github.com/damacaa/weird-engine
+ GIT_TAG main
+ )
+ FetchContent_MakeAvailable(WeirdEngine)
+endif()
+
+# Glob source files and header files from the proper directories.
+file(GLOB_RECURSE WEIRDGAME_SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp")
+file(GLOB_RECURSE WEIRDGAME_HEADERS
+ "${CMAKE_SOURCE_DIR}/include/*.h"
+ "${CMAKE_SOURCE_DIR}/include/*.hpp"
+)
+file(GLOB_RECURSE WEIRDGAME_ASSETS
+ "${CMAKE_SOURCE_DIR}/assets/*.*"
+)
+
+# Mark headers as header-only so that Visual Studio treats them appropriately.
+set_source_files_properties(${WEIRDGAME_HEADERS} PROPERTIES HEADER_FILE_ONLY TRUE)
+
+# Add executable including both sources and headers.
+add_executable(${PROJECT_NAME} ${WEIRDGAME_SOURCES} ${WEIRDGAME_HEADERS} ${WEIRDGAME_ASSETS})
+
+# Set include directories.
+target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include)
+
+# Link to WeirdEngine.
+target_link_libraries(${PROJECT_NAME} PRIVATE WeirdEngine)
+
+# Set Asset Path Macro
+# Define the assets path variable
+set(ASSETS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/assets/")
+# set(ASSETS_PATH "./assets") # Set the asset path macro in release mode to a relative path that assumes the assets folder is in the same directory as the game executable
+
+# Print the assets path for debugging or confirmation
+message(STATUS "Assets path: ${ASSETS_PATH}")
+
+# Use the variable in target_compile_definitions
+target_compile_definitions(${PROJECT_NAME} PUBLIC ASSETS_PATH="${ASSETS_PATH}")
+
+# Example for the future with more libraries
+add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+ # Command for SDL3
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ $
+ $
+
+ # Command for SDL3_image
+ # COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ # $ #<-- Note the target name might be different
+ # $
+
+ COMMENT "Copying runtime DLLs to executable directory"
+)
+
+# ----------------------------------------------------------
+# Helper function to assign source groups based on folder structure.
+function(assign_source_groups TARGET)
+ foreach(source_file IN LISTS ARGN)
+ # Get the full path to the file's directory.
+ get_filename_component(FILE_PATH "${source_file}" PATH)
+ # Compute the path relative to the project's root.
+ file(RELATIVE_PATH REL_PATH "${CMAKE_SOURCE_DIR}" "${FILE_PATH}")
+ # Replace forward slashes with backslashes for Visual Studio filter naming.
+ string(REPLACE "/" "\\" FILTER_PATH "${REL_PATH}")
+ if(FILTER_PATH STREQUAL "")
+ set(FILTER_PATH "Root")
+ endif()
+ # Assign the file to the computed filter.
+ source_group("${FILTER_PATH}" FILES "${source_file}")
+ endforeach()
+endfunction()
+
+# Assign source groups for all your files.
+assign_source_groups(${PROJECT_NAME} ${WEIRDGAME_SOURCES} ${WEIRDGAME_HEADERS} ${WEIRDGAME_ASSETS})
diff --git a/examples/sample-scenes/assets/fire/fire.jpg b/examples/sample-scenes/assets/fire/fire.jpg
new file mode 100644
index 0000000..eb060b3
Binary files /dev/null and b/examples/sample-scenes/assets/fire/fire.jpg differ
diff --git a/examples/sample-scenes/assets/fire/flame.png b/examples/sample-scenes/assets/fire/flame.png
new file mode 100644
index 0000000..dbb62a4
Binary files /dev/null and b/examples/sample-scenes/assets/fire/flame.png differ
diff --git a/examples/sample-scenes/assets/fire/flame.xcf b/examples/sample-scenes/assets/fire/flame.xcf
new file mode 100644
index 0000000..513671a
Binary files /dev/null and b/examples/sample-scenes/assets/fire/flame.xcf differ
diff --git a/examples/sample-scenes/assets/fire/flame2.png b/examples/sample-scenes/assets/fire/flame2.png
new file mode 100644
index 0000000..13c4181
Binary files /dev/null and b/examples/sample-scenes/assets/fire/flame2.png differ
diff --git a/examples/sample-scenes/assets/fire/shaders/fireParticles.frag b/examples/sample-scenes/assets/fire/shaders/fireParticles.frag
new file mode 100644
index 0000000..2c61a07
--- /dev/null
+++ b/examples/sample-scenes/assets/fire/shaders/fireParticles.frag
@@ -0,0 +1,16 @@
+#version 330 core
+
+out vec4 FragColor;
+
+// Inputs from vertex shader
+in vec3 v_worldPos;
+in vec3 v_normal;
+in vec3 v_color;
+in vec2 v_texCoord;
+
+uniform float u_time;
+
+void main()
+{
+ FragColor = vec4(vec3(1.75), 1.0);
+}
\ No newline at end of file
diff --git a/examples/sample-scenes/assets/fire/shaders/fireParticles.vert b/examples/sample-scenes/assets/fire/shaders/fireParticles.vert
new file mode 100644
index 0000000..9222af9
--- /dev/null
+++ b/examples/sample-scenes/assets/fire/shaders/fireParticles.vert
@@ -0,0 +1,50 @@
+#version 330 core
+
+// Vertex attributes
+layout (location = 0) in vec3 in_position;
+layout (location = 1) in vec3 in_normal;
+layout (location = 2) in vec3 in_color;
+layout (location = 3) in vec2 in_texCoord;
+
+// Outputs to fragment shader
+out vec3 v_worldPos;
+out vec3 v_normal;
+out vec3 v_color;
+out vec2 v_texCoord;
+
+// Uniforms
+uniform mat4 u_model;
+uniform mat4 u_camMatrix;
+uniform mat3 u_normalMatrix;
+
+uniform float u_time;
+
+// ChatGPT: I want a function that, for a given x, gros linearly but then plateaus
+float plateauFunction(float x, float maxValue, float growthRate)
+{
+ return maxValue * (1.0 - exp(-growthRate * x));
+}
+
+void main()
+{
+ // Animation delta
+ float delta = fract((10.0 * gl_InstanceID * 3.14) + (1.1 * u_time));
+
+ float maxHeight = 1.5 + (fract(gl_InstanceID * 123.45678) - 0.5); // Constant + random offset
+ float y = plateauFunction(2.0 * delta, maxHeight, 0.8);
+
+ float distanceToCenterXZ = 0.1 + (0.3 * smoothstep(0, 1, sqrt(1.5 * delta))); // TODO: find an alternative to sqrt
+
+ vec3 offset = vec3(
+ distanceToCenterXZ * sin(u_time + gl_InstanceID),
+ y,
+ distanceToCenterXZ * cos(u_time + gl_InstanceID)
+ );
+
+ v_worldPos = vec3(u_model * vec4(2.0 * (1.0 - delta * delta) * in_position, 1.0)) + offset;
+ v_normal = u_normalMatrix * in_normal;
+ v_color = in_color;
+ v_texCoord = in_texCoord;
+
+ gl_Position = u_camMatrix * vec4(v_worldPos, 1.0);
+}
\ No newline at end of file
diff --git a/examples/sample-scenes/assets/fire/shaders/flame.frag b/examples/sample-scenes/assets/fire/shaders/flame.frag
new file mode 100644
index 0000000..704690c
--- /dev/null
+++ b/examples/sample-scenes/assets/fire/shaders/flame.frag
@@ -0,0 +1,72 @@
+#version 330 core
+
+out vec4 FragColor;
+
+// Inputs from vertex shader
+in vec3 v_worldPos;
+in vec3 v_normal;
+in vec3 v_color;
+in vec2 v_texCoord;
+
+
+uniform float u_time;
+
+uniform sampler2D t_noise;
+uniform sampler2D t_flameShape;
+
+const int NUM_STOPS = 4;
+uniform vec3 colors[NUM_STOPS] = vec3[](
+ vec3(0.1, 0.1, 0.1), // Grey
+ vec3(0.8, 0.3, 0.2), // Red
+ vec3(1.1, 0.7, 0.2), // Orange
+ vec3(1.2, 1.2, 1.2) // White
+);
+
+uniform float stops[NUM_STOPS] = float[](0.0, 0.7, 0.9, 1.0);
+
+vec3 getGradientColor(float t)
+{
+ // This could be replace with a texture, but this approach makes it easier to iterate and choose colors
+ for (int i = 0; i < NUM_STOPS - 1; ++i) {
+ if (t >= stops[i] && t <= stops[i+1]) {
+ float localT = (t - stops[i]) / (stops[i+1] - stops[i]);
+ return mix(colors[i], colors[i+1], localT);
+ }
+ }
+
+ return colors[NUM_STOPS - 1]; // fallback
+}
+
+
+void main()
+{
+ vec2 uv = v_texCoord;
+
+ // Noise0
+ float noise0 = texture(t_noise, fract((3.0f * uv) - vec2(0.0f, u_time))).x - 0.5f;
+
+ // Noise1
+ float noise1 = texture(t_noise, fract((2.0 * uv) - vec2(0.0f, 1.2f * u_time))).x - 0.5f;
+
+ // Combine all noise
+ float sumNoise = noise0 + noise1;
+
+ // Reduce noise at the bottom of the flame
+ float noiseMask = clamp(3.0f * (v_texCoord.y - 0.35f), 0, 1);
+ sumNoise *= noiseMask;
+
+ // Reduce overall noise strength
+ float noiseIntensity = 0.1f;
+ sumNoise *= noiseIntensity;
+
+ // Sample texture with noise applied to uv coordinates
+ float alpha = texture(t_flameShape, clamp(uv + sumNoise, 0, 1)).x;
+
+ alpha = smoothstep(.3, 1.0, alpha);
+ alpha = alpha * (alpha + 0.01f);
+ alpha = clamp(alpha, 0.0, 1.0);
+
+ FragColor = vec4(getGradientColor(alpha), alpha);
+ // FragColor = vec4(vec3(sumNoise / noiseIntensity), 1.0f); // Debug noise
+ // FragColor = vec4(vec3(alpha), 1.0f); // Debug alpha
+}
\ No newline at end of file
diff --git a/examples/sample-scenes/assets/fire/shaders/heatDistortion.frag b/examples/sample-scenes/assets/fire/shaders/heatDistortion.frag
new file mode 100644
index 0000000..0d2e956
--- /dev/null
+++ b/examples/sample-scenes/assets/fire/shaders/heatDistortion.frag
@@ -0,0 +1,53 @@
+#version 330 core
+
+out vec4 FragColor;
+
+// Inputs from vertex shader
+in vec3 v_worldPos;
+in vec3 v_normal;
+in vec3 v_color;
+in vec2 v_texCoord;
+
+uniform sampler2D t_texture;
+uniform sampler2D t_noise;
+uniform sampler2D t_flameShape;
+
+uniform float u_time = 0.1f;
+uniform vec2 u_resolution;
+
+// Fog calculations used to modulate distortion with distance
+float linearDepth(float z, float near, float far)
+{
+ return (2.0 * near) / (far + near - z * (far - near));
+}
+
+void main()
+{
+ // Mesh uv to sample mask texture
+ vec2 uv = v_texCoord;
+ // Screen uv to sample scene texture
+ vec2 screenUV = gl_FragCoord.xy / u_resolution;
+
+ // Use the flame shape to mask the noise
+ float bottomFade = texture(t_flameShape, vec2(uv.x, min(uv.y, 0.5))).r;
+ bottomFade = smoothstep(0.5, 1.0, bottomFade);
+
+ // Fade at the top
+ float topFade = 1.0 - uv.y;
+ bottomFade *= topFade;
+
+ // Blur is less strong when its farther from the camera, same math as fog
+ float depthMask = max(1.0 - (linearDepth(gl_FragCoord.z, 0.1, 100.0) * 1.5), 0.0);
+
+ // Reduce strength when the flame is looking up
+ float dotWorldY = 1.0f - abs(dot(normalize(v_normal), vec3(0, 1, 0)));
+
+ // Combine all masks
+ float mask = bottomFade * depthMask * dotWorldY;
+
+ // Calculate scene texture uv offset
+ vec2 offset = vec2(0, mask * 0.1f * ((texture(t_noise, (2.0f * uv) - (1.0f * u_time)).x) - 0.5));
+
+ FragColor = texture(t_texture, screenUV + offset);
+ // FragColor = vec4(vec3(mask), 1.0); // Debug mask
+}
\ No newline at end of file
diff --git a/examples/sample-scenes/assets/fire/shaders/smokeParticles.frag b/examples/sample-scenes/assets/fire/shaders/smokeParticles.frag
new file mode 100644
index 0000000..6b3639d
--- /dev/null
+++ b/examples/sample-scenes/assets/fire/shaders/smokeParticles.frag
@@ -0,0 +1,25 @@
+#version 330 core
+
+out vec4 FragColor;
+
+// Inputs from vertex shader
+in vec3 v_worldPos;
+in vec3 v_normal;
+in vec3 v_color;
+in vec2 v_texCoord;
+in float v_delta;
+
+uniform float u_time;
+uniform vec3 u_smokeColor = vec3(0.12);
+
+void main()
+{
+ // Distance to center generates a circular gradient
+ float d = 2.0 * length(v_texCoord - vec2(0.5));
+ float alpha = max(0.0, 1.0 - d);
+
+ // Animate alpha
+ alpha *= pow(1.0 - v_delta, 2.0);
+
+ FragColor = vec4(u_smokeColor * (1.0 - v_delta), 0.75 * alpha);
+}
\ No newline at end of file
diff --git a/examples/sample-scenes/assets/fire/shaders/smokeParticles.vert b/examples/sample-scenes/assets/fire/shaders/smokeParticles.vert
new file mode 100644
index 0000000..b79a26c
--- /dev/null
+++ b/examples/sample-scenes/assets/fire/shaders/smokeParticles.vert
@@ -0,0 +1,61 @@
+#version 330 core
+
+// Vertex attributes
+layout (location = 0) in vec3 in_position;
+layout (location = 1) in vec3 in_normal;
+layout (location = 2) in vec3 in_color;
+layout (location = 3) in vec2 in_texCoord;
+
+// Outputs to fragment shader
+out vec3 v_worldPos;
+out vec3 v_normal;
+out vec3 v_color;
+out vec2 v_texCoord;
+
+out float v_delta;
+
+// Uniforms
+uniform mat4 u_model;
+uniform mat4 u_camMatrix;
+uniform mat3 u_normalMatrix;
+
+uniform float u_time;
+
+// ChatGPT: I want a function that, for a given x, increases but then plateaus
+float plateauFunction(float x, float maxValue, float growthRate)
+{
+ return maxValue * (1.0 - exp(-growthRate * x));
+}
+
+float rand(float x)
+{
+ return fract(sin(x) * 43758.5453123);
+}
+
+void main()
+{
+ // Animation delta
+ float delta = fract((gl_InstanceID * 123.45678f) + (0.1f * u_time));
+
+ // Position
+ vec3 offset = vec3(
+ delta * 5.0f * (rand(gl_InstanceID * 1.2345) - 0.5f),
+ delta * (7.0 + (3.0 * rand(gl_InstanceID * 1.2345))),
+ delta * 5.0f * (rand(gl_InstanceID * 0.9876) - 0.5f)
+ );
+
+ // Scale
+ float scale = 1.0 + (3.0 * delta);
+
+ v_worldPos = vec3(u_model * vec4(scale * in_position, 1.0)) + offset;
+ v_normal = u_normalMatrix * in_normal;
+ v_color = in_color;
+ v_texCoord = in_texCoord;
+
+ // Pass delta to fragment shader
+ v_delta = delta;
+
+ gl_Position = u_camMatrix * vec4(v_worldPos, 1.0);
+}
+
+
\ No newline at end of file
diff --git a/examples/sample-scenes/assets/jimmy.jpg b/examples/sample-scenes/assets/jimmy.jpg
new file mode 100644
index 0000000..9a4f1d2
Binary files /dev/null and b/examples/sample-scenes/assets/jimmy.jpg differ
diff --git a/examples/sample-scenes/assets/lines/combination.frag b/examples/sample-scenes/assets/lines/combination.frag
new file mode 100644
index 0000000..bd5be53
--- /dev/null
+++ b/examples/sample-scenes/assets/lines/combination.frag
@@ -0,0 +1,47 @@
+#version 330 core
+
+// Outputs colors in RGBA
+out vec4 FragColor;
+
+in vec2 v_texCoord;
+
+uniform sampler2D t_scene;
+uniform sampler2D t_lines;
+
+const int NUM_STOPS = 4;
+uniform vec3 colors[4] = vec3[](
+ vec3(0.82, 0.74, 0.88), // Muted lavender
+ vec3(0.78, 0.94, 0.76), // Pale pistachio
+ vec3(0.98, 0.85, 0.72), // Dusty pastel orange
+ vec3(0.68, 0.96, 0.95) // Soft cyan mist
+);
+
+
+uniform float stops[NUM_STOPS] = float[](0.0, 0.33, 0.66, 1.0);
+
+vec3 getGradientColor(float t)
+{
+ // This could be replace with a texture, but this approach makes it easier to iterate and choose colors
+ for (int i = 0; i < NUM_STOPS - 1; ++i) {
+ if (t >= stops[i] && t <= stops[i+1]) {
+ float localT = (t - stops[i]) / (stops[i+1] - stops[i]);
+ return mix(colors[i], colors[i+1], localT);
+ }
+ }
+
+ return colors[NUM_STOPS - 1]; // fallback
+}
+
+void main()
+{
+ vec2 uv = v_texCoord;
+
+ vec4 scene = texture(t_scene, uv);
+ vec4 lines = texture(t_lines, uv);
+
+ vec3 sceneFilter = getGradientColor(scene.r);
+
+ vec3 color = mix(vec3(0.576, 0.376, 0.729), sceneFilter, 1.0 - lines.a);
+
+ FragColor = vec4(color, 1.0);
+}
diff --git a/examples/sample-scenes/assets/lines/lines.frag b/examples/sample-scenes/assets/lines/lines.frag
new file mode 100644
index 0000000..c32e20f
--- /dev/null
+++ b/examples/sample-scenes/assets/lines/lines.frag
@@ -0,0 +1,38 @@
+#version 330 core
+
+// Outputs colors in RGBA
+out vec4 FragColor;
+
+in vec2 v_texCoord;
+
+uniform sampler2D t_sceneDepth;
+uniform vec2 u_pixelSize;
+
+float linearDepth(float z, float near, float far)
+{
+ return (2.0 * near) / (far + near - z * (far - near));
+}
+
+void main()
+{
+ vec2 uv = v_texCoord;
+ float depth = linearDepth(texture(t_sceneDepth, uv).x, 0.1, 100.0);
+
+ float maxDifference = 0.0;
+ vec2 offsets[4] = vec2[](
+ vec2(u_pixelSize.x, 0.0),
+ vec2(-u_pixelSize.x, 0.0),
+ vec2(0.0, u_pixelSize.y),
+ vec2(0.0, -u_pixelSize.y));
+
+ for (int i = 0; i < 4; i++)
+ {
+ float neighbor = texture(t_sceneDepth, uv + offsets[i]).x;
+ neighbor = linearDepth(neighbor, 0.1, 100.0);
+ float diff = neighbor - depth;
+ maxDifference = max(maxDifference, diff);
+ }
+
+ float alpha = maxDifference > 0.025 ? 1.0 : 0.0;
+ FragColor = vec4(vec3(1.0), alpha);
+}
diff --git a/examples/sample-scenes/assets/monkey/demo.bin b/examples/sample-scenes/assets/monkey/demo.bin
new file mode 100644
index 0000000..dc6e3e9
Binary files /dev/null and b/examples/sample-scenes/assets/monkey/demo.bin differ
diff --git a/examples/sample-scenes/assets/monkey/demo.gltf b/examples/sample-scenes/assets/monkey/demo.gltf
new file mode 100644
index 0000000..2b91503
--- /dev/null
+++ b/examples/sample-scenes/assets/monkey/demo.gltf
@@ -0,0 +1,104 @@
+{
+ "asset":{
+ "generator":"Khronos glTF Blender I/O v4.3.47",
+ "version":"2.0"
+ },
+ "scene":0,
+ "scenes":[
+ {
+ "name":"Scene",
+ "nodes":[
+ 0
+ ]
+ }
+ ],
+ "nodes":[
+ {
+ "mesh":0,
+ "name":"Suzanne"
+ }
+ ],
+ "meshes":[
+ {
+ "name":"Suzanne",
+ "primitives":[
+ {
+ "attributes":{
+ "POSITION":0,
+ "NORMAL":1,
+ "TEXCOORD_0":2
+ },
+ "indices":3
+ }
+ ]
+ }
+ ],
+ "accessors":[
+ {
+ "bufferView":0,
+ "componentType":5126,
+ "count":2109,
+ "max":[
+ 1.325934886932373,
+ 0.9392362236976624,
+ 0.8223199844360352
+ ],
+ "min":[
+ -1.325934886932373,
+ -0.9704862236976624,
+ -0.7782661318778992
+ ],
+ "type":"VEC3"
+ },
+ {
+ "bufferView":1,
+ "componentType":5126,
+ "count":2109,
+ "type":"VEC3"
+ },
+ {
+ "bufferView":2,
+ "componentType":5126,
+ "count":2109,
+ "type":"VEC2"
+ },
+ {
+ "bufferView":3,
+ "componentType":5123,
+ "count":11808,
+ "type":"SCALAR"
+ }
+ ],
+ "bufferViews":[
+ {
+ "buffer":0,
+ "byteLength":25308,
+ "byteOffset":0,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":25308,
+ "byteOffset":25308,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":16872,
+ "byteOffset":50616,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":23616,
+ "byteOffset":67488,
+ "target":34963
+ }
+ ],
+ "buffers":[
+ {
+ "byteLength":91104,
+ "uri":"demo.bin"
+ }
+ ]
+}
diff --git a/examples/sample-scenes/assets/water/shaders/water.frag b/examples/sample-scenes/assets/water/shaders/water.frag
new file mode 100644
index 0000000..6cd0ae1
--- /dev/null
+++ b/examples/sample-scenes/assets/water/shaders/water.frag
@@ -0,0 +1,45 @@
+#version 330 core
+
+out vec4 FragColor;
+
+// Inputs from vertex shader
+in vec3 v_worldPos;
+in vec3 v_normal;
+in vec3 v_color;
+in vec2 v_texCoord;
+
+uniform sampler2D t_texture;
+uniform sampler2D t_noise;
+
+uniform float u_time = 0.1f;
+uniform vec2 u_resolution;
+
+// Fog calculations used to modulate distortion with distance
+float linearDepth(float z, float near, float far)
+{
+ return (2.0 * near) / (far + near - z * (far - near));
+}
+
+void main()
+{
+ // Mesh uv to sample mask texture
+ vec2 uv = v_texCoord;
+ // Screen uv to sample scene texture
+ vec2 screenUV = gl_FragCoord.xy / u_resolution;
+
+
+ // Blur is less strong when its farther from the camera, same math as fog
+ float depthMask = max(1.0 - (linearDepth(gl_FragCoord.z, 0.1, 100.0) * 1.5), 0.0);
+
+ // Reduce strength when the flame is looking up
+ float dotWorldY = 1.0f - abs(dot(normalize(v_normal), vec3(0, 1, 0)));
+
+
+ // Calculate scene texture uv offset
+ vec2 offset = vec2(0.005 * sin(0.2 * gl_FragCoord.y + u_time), 0);
+ float maskk = 1.0 - clamp(0.05 * length(v_worldPos), 0.0, 1.0);
+ vec4 backgroundColor = texture(t_texture, screenUV + (maskk * offset)) + (maskk * 0.1);
+
+ FragColor = backgroundColor;
+ // FragColor = vec4(vec3(maskk), 1.0); // Debug mask
+}
\ No newline at end of file
diff --git a/examples/sample-scenes/include/ApparentCircularMotionScene.h b/examples/sample-scenes/include/ApparentCircularMotionScene.h
new file mode 100644
index 0000000..ce082b0
--- /dev/null
+++ b/examples/sample-scenes/include/ApparentCircularMotionScene.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include
+
+using namespace WeirdEngine;
+class ApparentCircularMotionScene : public Scene
+{
+private:
+ // Inherited via Scene
+ uint16_t m_count = 8;
+ std::vector m_circles;
+
+ void onStart() override
+ {
+ m_simulation2D.setDamping(0.0f);
+ m_simulation2D.setGravity(0.0f);
+
+ for (size_t i = 0; i < m_count; i++)
+ {
+ Entity entity = m_ecs.createEntity();
+
+ Transform& t = m_ecs.addComponent(entity);
+ t.position = vec3(0, 0, 0);
+
+ SDFRenderer& sdfRenderer = m_ecs.addComponent(entity);
+ sdfRenderer.materialId = i % 16;
+ RigidBody2D& rb = m_ecs.addComponent(entity);
+
+ m_circles.push_back(entity);
+ }
+ }
+
+ void onUpdate(float delta) override
+ {
+ auto time = getTime();
+
+ if (time > 1)
+ {
+ // return;
+ }
+
+ for (size_t i = 0; i < m_count; i++)
+ {
+ float angle = 1 * 3.1416 * i / m_count;
+ auto& t = m_ecs.getComponent(m_circles[i]);
+ t.position = (10.0f * ((float)sin(time + angle)) * vec3(cos(angle), sin(angle), 0)) + vec3(15, 15, 0);
+ t.isDirty = true;
+ }
+ }
+};
diff --git a/examples/sample-scenes/include/Classic.h b/examples/sample-scenes/include/Classic.h
new file mode 100644
index 0000000..500d0e8
--- /dev/null
+++ b/examples/sample-scenes/include/Classic.h
@@ -0,0 +1,64 @@
+#pragma once
+
+#include
+
+using namespace WeirdEngine;
+class ClassicScene : public Scene
+{
+private:
+
+ Entity m_monkey;
+ Entity m_ball;
+
+ // Inherited via Scene
+ void onStart() override
+ {
+ m_renderMode = RenderMode::RayMarching3D;
+
+ {
+ Entity entity = m_ecs.createEntity();
+ Transform& t = m_ecs.addComponent(entity);
+ t.position = vec3(0,0,0);
+
+ MeshRenderer& mr = m_ecs.addComponent(entity);
+
+ auto id = m_resourceManager.getMeshId(ASSETS_PATH "monkey/demo.gltf", entity, true);
+ mr.mesh = id;
+
+ m_monkey = entity;
+ }
+
+ {
+ Entity entity = m_ecs.createEntity();
+ Transform& t = m_ecs.addComponent(entity);
+ t.position = vec3(0, 1, 0);
+
+ auto& sdf = m_ecs.addComponent(entity);
+ sdf.materialId = 0;
+
+ m_ball = entity;
+ }
+ }
+
+ void onUpdate(float delta) override
+ {
+ Transform& cameraTransform = m_ecs.getComponent(m_mainCamera);
+
+ {
+ Transform& t = m_ecs.getComponent(m_monkey);
+ // t.position.z = 10 * sinf(getTime());
+ t.rotation.y = getTime();
+ t.position.y = 1.0f;
+ }
+
+ {
+ Transform& t = m_ecs.getComponent(m_ball);
+ // t.position.z = 10 * sinf(getTime());
+ t.position.x = 2.0f * sinf(-getTime());
+ t.position.z = 2.0f * cosf(-getTime());
+
+ }
+
+ // t.position = cameraTransform.position + vec3(-10, -6, -20);
+ }
+};
\ No newline at end of file
diff --git a/examples/sample-scenes/include/CollisionHandling.h b/examples/sample-scenes/include/CollisionHandling.h
new file mode 100644
index 0000000..a016712
--- /dev/null
+++ b/examples/sample-scenes/include/CollisionHandling.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include
+#include
+
+using namespace WeirdEngine;
+class CollisionHandlingScene : public Scene
+{
+public:
+ CollisionHandlingScene()
+ : Scene() {
+ };
+
+private:
+ // Inherited via Scene
+ void onStart() override
+ {
+ // Create a random number generator engine
+
+ for (size_t i = 0; i < 10; i++)
+ {
+ float y = 10 + i;
+ float x = 2 * i;
+
+ int material = 4 + (i % 12);
+
+ float z = 0;
+
+ Entity entity = m_ecs.createEntity();
+ Transform &t = m_ecs.addComponent(entity);
+ t.position = vec3(x + 0.5f, y + 0.5f, z);
+
+ SDFRenderer &sdfRenderer = m_ecs.addComponent(entity);
+ sdfRenderer.materialId = material;
+
+ RigidBody2D &rb = m_ecs.addComponent(entity);
+ }
+
+ // Floor
+ {
+ float variables[8]{0.5f, 1.5f, -1.0f};
+ addShape(0, variables, 3);
+ }
+
+ // Wall right
+ {
+ float variables[8]{30 + 5, 0, 5.0f, 30.0f, 0.0f};
+ addShape(m_sdfs.size() - 1, variables, 3);
+ }
+
+ // Wall left
+ {
+ float variables[8]{-5, 0, 5.0f, 30.0f, 0.0f};
+ addShape(m_sdfs.size() - 1, variables, 3);
+ }
+
+ m_ecs.getComponent(m_mainCamera).targetPosition = vec3(15.0f, 15.0f, 10.0f);
+ m_ecs.getComponent(m_mainCamera).position = vec3(15.0f, 15.0f, 10.0f);
+ }
+
+ void onUpdate(float delta) override
+ {
+ }
+
+ float m_lastTime = 0.0f;
+ void onCollision(WeirdEngine::CollisionEvent &event) override
+ {
+ float t = getTime();
+ if (t - m_lastTime < 0.1f)
+ return; // Avoid multiple collisions in a short time
+
+ m_lastTime = t;
+ // m_simulation2D.setPosition(event.bodyA, vec2(15.0f, 15.0f));
+ // m_simulation2D.addForce(event.bodyA, vec2(2.0f * sinf(t), -20.0f));
+ m_simulation2D.addForce(event.bodyB, vec2(0.0f, 10.0f));
+
+ // Entity a = m_ecs.getComponentArray()->getDataAtIdx(event.bodyA).Owner;
+ // Transform &at = m_ecs.getComponent(a);
+ // at.position.x = 15.0f + sinf(event.bodyB * 123.4565f + t);
+ // at.position.y = 5.0f + (event.bodyA % 10) * 2.5f;
+ // at.isDirty = true;
+ }
+};
diff --git a/examples/sample-scenes/include/DestroyScene.h b/examples/sample-scenes/include/DestroyScene.h
new file mode 100644
index 0000000..a311d45
--- /dev/null
+++ b/examples/sample-scenes/include/DestroyScene.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include
+
+using namespace WeirdEngine;
+class DestroyScene : public Scene
+{
+public:
+ DestroyScene()
+ : Scene() {
+ };
+
+private:
+ std::array m_testEntity;
+ bool m_testEntityCreated = false;
+
+ float m_lastSpawnTime = 0.0f;
+
+ void onUpdate(float delta) override
+ {
+ if (m_testEntityCreated && (getTime() - m_lastSpawnTime) > 0.5f && Input::GetKeyDown(Input::U))
+ {
+ for (size_t i = 0; i < m_testEntity.size(); i++)
+ {
+ m_ecs.destroyEntity(m_testEntity[i]);
+ }
+
+ m_testEntityCreated = false;
+ }
+ else if (!m_testEntityCreated)
+ {
+ for (size_t i = 0; i < m_testEntity.size(); i++)
+ {
+ Entity entity = m_ecs.createEntity();
+ Transform& t = m_ecs.addComponent(entity);
+ t.position = vec3(15.0f + (i % 10), 30.0f + (i / 10), 0.0f);
+ t.isDirty = true;
+
+ SDFRenderer& sdfRenderer = m_ecs.addComponent(entity);
+ sdfRenderer.materialId = 4 + m_ecs.getComponentArray()->getSize() % 12;
+
+ RigidBody2D& rb = m_ecs.addComponent(entity);
+ m_simulation2D.addForce(rb.simulationId, vec2(0, -50));
+
+ m_testEntity[i] = entity;
+ }
+
+ m_testEntityCreated = true;
+ m_lastSpawnTime = getTime();
+ }
+
+ if (m_testEntityCreated && Input::GetKeyDown(Input::I))
+ {
+ for (size_t i = 0; i < m_testEntity.size(); i++)
+ {
+ RigidBody2D& rb = m_ecs.getComponent(m_testEntity[i]);
+
+ if (i > 0)
+ {
+ m_simulation2D.addSpring(rb.simulationId, rb.simulationId - 1, 1000000.0f);
+ }
+ else
+ {
+ m_simulation2D.setPosition(rb.simulationId, vec2(0, 15));
+ m_simulation2D.fix(rb.simulationId);
+ }
+ }
+ }
+ }
+
+ // Inherited via Scene
+ void onStart() override
+ {
+ {
+ float variables[8]{ 0.0f, 0.0f };
+ addShape(0, variables, 3);
+ }
+ }
+};
diff --git a/examples/sample-scenes/include/Fire.h b/examples/sample-scenes/include/Fire.h
new file mode 100644
index 0000000..ea7cfed
--- /dev/null
+++ b/examples/sample-scenes/include/Fire.h
@@ -0,0 +1,474 @@
+#pragma once
+
+#include
+
+using namespace WeirdEngine;
+class FireScene : public Scene
+{
+private:
+ Shader m_flameShader;
+ Shader m_particlesShader;
+ Shader m_smokeShader;
+ Shader m_litShader;
+ Shader m_heatDistortionShader;
+ Shader m_blurShader;
+ Shader m_bloomShader;
+ Shader m_brightFilterShader;
+ Shader m_backgroundShader;
+
+ Mesh *m_quad = nullptr;
+ Mesh *m_cube = nullptr;
+
+ Texture *m_noiseTexture = nullptr;
+ Texture *m_flameShape = nullptr;
+ Texture *m_sceneTextureBeforeFire = nullptr; // Copy of scene texture for heat effect
+ Texture *m_postProcessTextureFront = nullptr;
+ Texture *m_postProcessTextureBack = nullptr;
+ Texture *m_brightPassTexture = nullptr;
+
+ RenderTarget *m_postProcessRenderFront;
+ RenderTarget *m_postProcessRenderBack;
+ RenderTarget *m_bloomRenderTarget;
+
+ RenderTarget *m_postProcessDoubleBuffer[2];
+
+ RenderPlane m_renderPlane;
+
+ std::vector m_lights;
+
+ void onCreate() override
+ {
+ m_renderMode = RenderMode::Simple3D;
+
+ // Base shaders
+ m_backgroundShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "backgroundGrid.frag");
+ m_litShader = Shader(SHADERS_PATH "default.vert", SHADERS_PATH "lit.frag");
+ m_bloomShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "bloom.frag");
+ m_blurShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "blur.frag");
+ m_brightFilterShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "brightFilter.frag");
+
+ // Custom shaders
+ m_flameShader = Shader(SHADERS_PATH "default.vert", ASSETS_PATH "fire/shaders/flame.frag");
+ m_particlesShader = Shader(ASSETS_PATH "fire/shaders/fireParticles.vert", ASSETS_PATH "fire/shaders/fireParticles.frag");
+ m_smokeShader = Shader(ASSETS_PATH "fire/shaders/smokeParticles.vert", ASSETS_PATH "fire/shaders/smokeParticles.frag");
+ m_heatDistortionShader = Shader(SHADERS_PATH "default.vert", ASSETS_PATH "fire/shaders/heatDistortion.frag");
+
+ m_lights.push_back(
+ Light{
+ 0,
+ glm::vec3(0.0f, 1.0f, 0.0f),
+ 0,
+ glm::vec3(0.0f),
+ glm::vec4(1.0f, 0.95f, 0.9f, 2.0f)});
+
+ // Load meshes
+ // Quad geom
+ {
+ float size = 0.5f;
+ std::vector vertices = {
+ // positions // normals // colors // UVs
+ {{-size, -size, 0.f}, {0.f, 0.f, 1.f}, {1.f, 1.f, 1.f}, {0.f, 0.f}}, // bottom left
+ {{size, -size, 0.f}, {0.f, 0.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 0.f}}, // bottom right
+ {{size, size, 0.f}, {0.f, 0.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f}}, // top right
+ {{-size, size, 0.f}, {0.f, 0.f, 1.f}, {1.f, 1.f, 1.f}, {0.f, 1.f}} // top left
+ };
+
+ std::vector indices = {
+ 0, 2, 1, // first triangle
+ 3, 2, 0 // second triangle
+ };
+
+ std::vector textures = {};
+ m_quad = new Mesh(1, vertices, indices, textures);
+ m_quad->m_isBillboard = true;
+ }
+
+ // Cube geom
+ {
+ float size = 0.5f;
+ std::vector vertices = {
+ // positions // normals // colors // UVs
+ // Front face
+ {{-size, -size, size}, {0.f, 0.f, 1.f}, {1.f, 1.f, 1.f}, {0.f, 0.f}},
+ {{size, -size, size}, {0.f, 0.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 0.f}},
+ {{size, size, size}, {0.f, 0.f, 1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f}},
+ {{-size, size, size}, {0.f, 0.f, 1.f}, {1.f, 1.f, 1.f}, {0.f, 1.f}},
+
+ // Back face
+ {{-size, -size, -size}, {0.f, 0.f, -1.f}, {1.f, 1.f, 1.f}, {1.f, 0.f}},
+ {{size, -size, -size}, {0.f, 0.f, -1.f}, {1.f, 1.f, 1.f}, {0.f, 0.f}},
+ {{size, size, -size}, {0.f, 0.f, -1.f}, {1.f, 1.f, 1.f}, {0.f, 1.f}},
+ {{-size, size, -size}, {0.f, 0.f, -1.f}, {1.f, 1.f, 1.f}, {1.f, 1.f}},
+
+ // Left face
+ {{-size, -size, -size}, {-1.f, 0.f, 0.f}, {1.f, 1.f, 1.f}, {0.f, 0.f}},
+ {{-size, -size, size}, {-1.f, 0.f, 0.f}, {1.f, 1.f, 1.f}, {1.f, 0.f}},
+ {{-size, size, size}, {-1.f, 0.f, 0.f}, {1.f, 1.f, 1.f}, {1.f, 1.f}},
+ {{-size, size, -size}, {-1.f, 0.f, 0.f}, {1.f, 1.f, 1.f}, {0.f, 1.f}},
+
+ // Right face
+ {{size, -size, size}, {1.f, 0.f, 0.f}, {1.f, 1.f, 1.f}, {0.f, 0.f}},
+ {{size, -size, -size}, {1.f, 0.f, 0.f}, {1.f, 1.f, 1.f}, {1.f, 0.f}},
+ {{size, size, -size}, {1.f, 0.f, 0.f}, {1.f, 1.f, 1.f}, {1.f, 1.f}},
+ {{size, size, size}, {1.f, 0.f, 0.f}, {1.f, 1.f, 1.f}, {0.f, 1.f}},
+
+ // Top face
+ {{-size, size, size}, {0.f, 1.f, 0.f}, {1.f, 1.f, 1.f}, {0.f, 0.f}},
+ {{size, size, size}, {0.f, 1.f, 0.f}, {1.f, 1.f, 1.f}, {1.f, 0.f}},
+ {{size, size, -size}, {0.f, 1.f, 0.f}, {1.f, 1.f, 1.f}, {1.f, 1.f}},
+ {{-size, size, -size}, {0.f, 1.f, 0.f}, {1.f, 1.f, 1.f}, {0.f, 1.f}},
+
+ // Bottom face
+ {{-size, -size, -size}, {0.f, -1.f, 0.f}, {1.f, 1.f, 1.f}, {0.f, 0.f}},
+ {{size, -size, -size}, {0.f, -1.f, 0.f}, {1.f, 1.f, 1.f}, {1.f, 0.f}},
+ {{size, -size, size}, {0.f, -1.f, 0.f}, {1.f, 1.f, 1.f}, {1.f, 1.f}},
+ {{-size, -size, size}, {0.f, -1.f, 0.f}, {1.f, 1.f, 1.f}, {0.f, 1.f}},
+ };
+
+ std::vector indices = {
+ // Front face
+ 0, 2, 1, 2, 0, 3,
+ // Back face
+ 7, 5, 6, 5, 7, 4,
+ // Left face
+ 11, 10, 9, 9, 8, 11,
+ // Right face
+ 12, 14, 13, 15, 14, 12,
+ // Top face
+ 19, 18, 17, 17, 16, 19,
+ // Bottom face
+ 22, 21, 20, 20, 23, 22};
+
+ std::vector textures = {};
+ m_cube = new Mesh(2, vertices, indices, textures);
+ }
+
+ // Fire textures
+ m_noiseTexture = new Texture(ASSETS_PATH "fire/fire.jpg");
+ m_flameShape = new Texture(ASSETS_PATH "fire/flame.png");
+
+ m_sceneTextureBeforeFire = new Texture(Screen::rWidth, Screen::rHeight, Texture::TextureType::Data);
+ m_postProcessTextureFront = new Texture(Screen::rWidth, Screen::rHeight, Texture::TextureType::Data);
+ m_postProcessTextureBack = new Texture(Screen::rWidth, Screen::rHeight, Texture::TextureType::Data);
+
+ m_postProcessRenderFront = new RenderTarget(false);
+ m_postProcessRenderFront->bindColorTextureToFrameBuffer(*m_postProcessTextureFront);
+
+ m_postProcessRenderBack = new RenderTarget(false);
+ m_postProcessRenderBack->bindColorTextureToFrameBuffer(*m_postProcessTextureBack);
+
+ m_postProcessDoubleBuffer[0] = m_postProcessRenderFront;
+ m_postProcessDoubleBuffer[1] = m_postProcessRenderBack;
+
+ // Bloom Texture and Render Target
+ m_brightPassTexture = new Texture(Screen::rWidth, Screen::rHeight, Texture::TextureType::Data);
+ m_bloomRenderTarget = new RenderTarget(false);
+ m_bloomRenderTarget->bindColorTextureToFrameBuffer(*m_brightPassTexture);
+ }
+
+ void onDestroy() override
+ {
+ m_flameShader.free();
+ m_particlesShader.free();
+ m_smokeShader.free();
+ m_litShader.free();
+ m_heatDistortionShader.free();
+ m_blurShader.free();
+ m_bloomShader.free();
+ m_brightFilterShader.free();
+ m_backgroundShader.free();
+
+ m_quad->free();
+ delete m_quad;
+ m_cube->free();
+ delete m_quad;
+
+ m_noiseTexture->dispose();
+ delete m_noiseTexture;
+ m_flameShape->dispose();
+ delete m_flameShape;
+ m_sceneTextureBeforeFire->dispose();
+ delete m_sceneTextureBeforeFire;
+ m_postProcessTextureFront->dispose();
+ delete m_postProcessTextureFront;
+ m_postProcessTextureBack->dispose();
+ delete m_postProcessTextureBack;
+ m_brightPassTexture->dispose();
+ delete m_brightPassTexture;
+
+ m_postProcessRenderFront->free();
+ delete m_postProcessRenderFront;
+ m_postProcessRenderBack->free();
+ delete m_postProcessRenderBack;
+ m_bloomRenderTarget->free();
+ delete m_bloomRenderTarget;
+
+ m_renderPlane.free();
+ }
+
+ // Inherited via Scene
+ void onStart() override
+ {
+ m_debugFly = false;
+ }
+
+ float m_time = 3.1416f;
+ void onUpdate(float delta) override
+ {
+ if (m_debugFly)
+ {
+ return;
+ }
+
+ if (!Input::GetKey(Input::Space))
+ {
+ static float speed = 0.15f;
+ if (Input::GetKey(Input::R))
+ {
+ m_time -= delta * speed;
+ }
+ else
+ {
+ m_time += delta * speed;
+ }
+ }
+
+ Transform &cameraTransform = m_ecs.getComponent(m_mainCamera);
+
+ static float amplitude = 12.5f;
+
+ cameraTransform.position.y = 2.0f + tan(0.5f * m_time);
+ cameraTransform.position.x = amplitude * sin(m_time);
+ cameraTransform.position.z = amplitude * cos(m_time);
+
+ cameraTransform.rotation = -cameraTransform.position;
+ }
+
+ void renderFire(WeirdRenderer::Camera &camera, float time)
+ {
+ // Particles
+ m_particlesShader.use();
+ m_particlesShader.setUniform("u_camMatrix", camera.cameraMatrix);
+ m_particlesShader.setUniform("u_camPos", camera.position);
+ m_particlesShader.setUniform("u_time", time);
+ m_quad->drawInstances(m_particlesShader, camera,
+ 10,
+ vec3(0, 1.0f, 0),
+ vec3(0, 0, time),
+ vec3(0.01f));
+
+ glEnable(GL_BLEND);
+
+ // Smoke
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDepthMask(GL_FALSE); // Don't write to the depth buffer
+
+ m_smokeShader.use();
+ m_smokeShader.setUniform("u_camMatrix", camera.cameraMatrix);
+ m_smokeShader.setUniform("u_camPos", camera.position);
+ m_smokeShader.setUniform("u_time", time);
+ m_quad->drawInstances(m_smokeShader, camera,
+ 50,
+ vec3(0, 1.0f, -0.1f),
+ vec3(0, 0, time),
+ vec3(1.0f));
+
+ glDepthMask(GL_TRUE);
+
+ // Fire
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ m_flameShader.use();
+ m_flameShader.setUniform("u_camMatrix", camera.cameraMatrix);
+ m_flameShader.setUniform("u_camPos", camera.position);
+ m_flameShader.setUniform("u_time", time);
+
+ m_flameShader.setUniform("t_noise", 0);
+ m_noiseTexture->bind(0);
+
+ m_flameShader.setUniform("t_flameShape", 1);
+ m_flameShape->bind(1);
+
+ // draw flame
+ m_quad->draw(m_flameShader, camera, vec3(0, 1.15f, 0), vec3(0, 0, 0), vec3(6));
+
+ m_noiseTexture->unbind();
+
+ glDisable(GL_BLEND);
+ }
+
+ void onRender(WeirdRenderer::RenderTarget &renderTarget) override
+ {
+
+ WeirdRenderer::Camera &sceneCamera = getCamera();
+ float time = getTime();
+
+ glDepthMask(GL_FALSE);
+ m_backgroundShader.use();
+ m_backgroundShader.setUniform("u_camMatrix", sceneCamera.cameraMatrix);
+ float shaderFov = 1.0f / tan(sceneCamera.fov * 0.01745f * 0.5f);
+ m_backgroundShader.setUniform("u_fov", shaderFov);
+
+ // m_renderPlane.draw(m_backgroundShader);
+ // glFrontFace(GL_CW); // Clockwise = front face
+ // m_cube->draw(m_backgroundShader, sceneCamera, sceneCamera.position, vec3(0.0f), vec3(100.0f));
+ // glFrontFace(GL_CCW); // Counter-clockwise = front face (default)
+
+ glDepthMask(GL_TRUE);
+
+ GL_CHECK_ERROR();
+
+ // Render stuff
+ m_litShader.use();
+ m_litShader.setUniform("u_time", (float)time);
+ m_litShader.setUniform("u_ambient", 0.025f);
+
+ // Take care of the camera Matrix
+ m_litShader.setUniform("u_camPos", sceneCamera.position);
+ m_litShader.setUniform("u_camMatrix", sceneCamera.cameraMatrix);
+
+ // Pass light rotation
+ glm::vec3 position = m_lights[0].position;
+ m_litShader.setUniform("u_lightPos", position);
+ glm::vec3 direction = m_lights[0].rotation;
+ m_litShader.setUniform("u_directionalLightDir", direction);
+ glm::vec4 color = m_lights[0].color;
+ m_litShader.setUniform("u_lightColor", color);
+
+ // bind current FBO
+ // m_sceneRender->bind(); // TODO: keep rendering to the same fbo. Should pass the render target and the color and depth textures
+
+ // Floor
+ m_cube->draw(m_litShader, sceneCamera, vec3(0, -500.0f, 0), vec3(0), vec3(4, 1000, 4));
+
+ m_cube->draw(m_litShader, sceneCamera, vec3(0.2f, 1.75f, -2.5f), vec3(-3.14f / 4.0f), vec3(1));
+
+ // m_monkey->draw(m_litShader, sceneCamera, vec3(0, 1, -2.5f), vec3(0, (-3.14f / 2.0f), 0), vec3(1));
+ m_cube->draw(m_litShader, sceneCamera, vec3(0.8f, 1.0f, 2.5f), vec3(0.5f, 0.5f, 0), vec3(1));
+ // m_cube->draw(m_litShader, sceneCamera, vec3(0.3f, 0.5f, 3.2f), vec3(0, 1.2f, 0), vec3(1));
+ // m_cube->draw(m_litShader, sceneCamera, vec3(0.9f, 1.5f, 2.9f), vec3(0, 0.75f, 0), vec3(1));
+
+ m_cube->draw(m_litShader, sceneCamera, vec3(-2.0f, 2.75f, 0.9f), vec3(-0.75f, 0.0f, 0), vec3(1));
+
+
+ GL_CHECK_ERROR();
+
+ // m_cube->draw(m_litShader, sceneCamera, vec3(0, 0.0f, 0), vec3(0), vec3(0.1f, 2.0f, 0.1f));
+
+ // Heat effect
+
+ // Don't write to depth buffer
+ glDepthMask(GL_FALSE);
+
+ // Copy scene texture // TODO: replace with glCopyTexSubImage which copies from the current read framebuffer attachment to the given image
+ glCopyImageSubData(
+ renderTarget.getColorAttachment()->ID, GL_TEXTURE_2D, 0, 0, 0, 0, // 2 = scene texture
+ m_sceneTextureBeforeFire->ID, GL_TEXTURE_2D, 0, 0, 0, 0,
+ Screen::rWidth, Screen::rHeight, 1);
+
+ // Heat effect shader
+ m_heatDistortionShader.use();
+ m_heatDistortionShader.setUniform("u_camPos", sceneCamera.position);
+ m_heatDistortionShader.setUniform("u_camMatrix", sceneCamera.cameraMatrix);
+
+ // Takes copy texture
+ m_heatDistortionShader.setUniform("t_texture", 0);
+ m_sceneTextureBeforeFire->bind(0);
+ // Noise texture
+ m_heatDistortionShader.setUniform("t_noise", 1);
+ m_noiseTexture->bind(1);
+ // Flame texture
+ m_heatDistortionShader.setUniform("t_flameShape", 2);
+ m_flameShape->bind(2);
+
+ GL_CHECK_ERROR();
+
+ // Time to animate effect
+ m_heatDistortionShader.setUniform("u_time", (float)time);
+ // Screen resolution to calculate screen uvs
+ m_heatDistortionShader.setUniform("u_resolution", glm::vec2(Screen::rWidth, Screen::rHeight));
+
+ // Render quad
+ m_quad->draw(m_heatDistortionShader, sceneCamera, vec3(0, 1.25f, 0), vec3(0, 0, 0), vec3(6));
+
+ // Write to depth buffer
+ glDepthMask(GL_TRUE);
+
+ // Fire
+ renderFire(sceneCamera, time);
+
+ if (Input::GetKey(Input::P))
+ {
+ return;
+ }
+
+ // Post processing
+ m_bloomRenderTarget->bind();
+ m_brightFilterShader.use();
+ m_brightFilterShader.setUniform("t_colorTexture", 0);
+ renderTarget.getColorAttachment()->bind(0);
+
+ m_renderPlane.draw(m_brightFilterShader);
+
+ m_blurShader.use();
+ m_blurShader.setUniform("t_colorTexture", 0);
+
+ bool horizontal = true;
+ static int amount = 10;
+
+ for (unsigned int i = 0; i < amount; i++)
+ {
+ m_postProcessDoubleBuffer[horizontal]->bind();
+
+ m_blurShader.setUniform("u_horizontal", horizontal);
+ if (i == 0)
+ {
+ m_brightPassTexture->bind(0);
+ }
+ else
+ {
+ m_postProcessDoubleBuffer[!horizontal]->getColorAttachment()->bind(0);
+ }
+
+ m_renderPlane.draw(m_blurShader);
+
+ horizontal = !horizontal;
+ }
+
+ // bind a different FBO
+ renderTarget.bind(); // bind to fbo 0
+
+ glDisable(GL_DEPTH_TEST);
+
+ // Use scene texture and a shader to apply pp
+ m_bloomShader.use();
+ m_bloomShader.setUniform("t_sceneTexture", 0);
+ renderTarget.getColorAttachment()->bind(0);
+
+ m_bloomShader.setUniform("t_blurTexture", 1);
+ RenderTarget *finalTarget = m_postProcessDoubleBuffer[!horizontal];
+ finalTarget->getColorAttachment()->bind(1);
+
+ if (Input::GetKey(Input::B))
+ {
+ finalTarget->getColorAttachment()->bind(0);
+ }
+
+ m_bloomShader.setUniform("u_pixelOffset", vec2(0.5f / Screen::rWidth, 0.5f / Screen::rHeight));
+
+ m_renderPlane.draw(m_bloomShader);
+ }
+};
+
+class FireSceneRayMarching : public FireScene
+{
+private:
+ void onStart() override
+ {
+ m_renderMode = RenderMode::RayMarching3D;
+
+ Transform& cameraTransform = m_ecs.getComponent(m_mainCamera);
+
+ cameraTransform.position = vec3(0.0f, 1.0f, 10.0f);
+ cameraTransform.rotation = vec3(0.0f, 0.0f, -1.0f);
+ }
+};
\ No newline at end of file
diff --git a/examples/sample-scenes/include/FireworksScene.h b/examples/sample-scenes/include/FireworksScene.h
new file mode 100644
index 0000000..446e616
--- /dev/null
+++ b/examples/sample-scenes/include/FireworksScene.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include
+#include
+
+using namespace WeirdEngine;
+class FireworksScene : public Scene
+{
+public:
+ FireworksScene()
+ : Scene() {
+ };
+
+private:
+ // Inherited via Scene
+ void onStart() override
+ {
+ // Create a random number generator engine
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ float range = 0.5f;
+ std::uniform_real_distribution<> distrib(-range, range);
+
+ for (size_t i = 0; i < 60; i++)
+ {
+ float y = 50 + distrib(gen);
+ float x = 15 + distrib(gen);
+
+ int material = 4 + (i % 12);
+
+ float z = 0;
+
+ Entity entity = m_ecs.createEntity();
+ Transform& t = m_ecs.addComponent(entity);
+ t.position = vec3(x + 0.5f, y + 0.5f, z);
+
+ if (i < 100)
+ {
+ }
+ SDFRenderer& sdfRenderer = m_ecs.addComponent(entity);
+ sdfRenderer.materialId = material;
+
+ RigidBody2D& rb = m_ecs.addComponent(entity);
+ }
+
+ // Floor
+ {
+ float variables[8]{ 0.5f, 1.5f, -1.0f };
+ addShape(0, variables, 3);
+ }
+ }
+
+ void onUpdate(float delta) override
+ {
+ }
+};
diff --git a/examples/sample-scenes/include/ImageScene.h b/examples/sample-scenes/include/ImageScene.h
new file mode 100644
index 0000000..2212763
--- /dev/null
+++ b/examples/sample-scenes/include/ImageScene.h
@@ -0,0 +1,168 @@
+#pragma once
+
+#include
+
+using namespace WeirdEngine;
+class ImageScene : public Scene
+{
+public:
+ ImageScene()
+ : Scene() {
+ };
+
+private:
+ std::string binaryString;
+ std::string filePath = "cache/image.txt";
+ std::string imagePath = "SampleProject/Resources/Textures/image.jpg";
+
+ // Inherited via Scene
+ void onStart() override
+ {
+ // Check if the folder exists
+ if (!std::filesystem::exists("cache/"))
+ {
+ // If it doesn't exist, create the folder
+ std::filesystem::create_directory("cache/");
+ }
+
+ if (checkIfFileExists(filePath.c_str()))
+ {
+ binaryString = get_file_contents(filePath.c_str());
+ }
+ else
+ {
+ binaryString = "0";
+ }
+
+ uint32_t currentChar = 0;
+
+ // Spawn 2d balls
+ for (size_t i = 0; i < 1200; i++)
+ {
+ float x;
+ float y;
+ int material = 0;
+
+ x = 15 + sin(i);
+ y = 10 + (1.0f * i);
+
+ std::string materialId;
+ while (currentChar < binaryString.size() && binaryString[currentChar] != '-')
+ {
+ materialId += binaryString[currentChar++];
+ }
+ currentChar++;
+
+ material = (materialId.size() > 0 && materialId.size() <= 2) ? std::stoi(materialId) : 0;
+
+ Entity entity = m_ecs.createEntity();
+ Transform& t = m_ecs.addComponent(entity);
+ t.position = vec3(x + 0.5f, y + 0.5f, 0);
+
+ SDFRenderer& sdfRenderer = m_ecs.addComponent(entity);
+ sdfRenderer.materialId = material;
+
+ RigidBody2D& rb = m_ecs.addComponent(entity);
+ }
+
+ // Floor
+ {
+ float variables[8]{ 15, -5, 25.0f, 5.0f, 0.0f };
+ addShape(m_sdfs.size() - 1, variables, 3);
+ }
+
+ // Wall right
+ {
+ float variables[8]{ 30 + 5, 20, 5.0f, 30.0f, 0.0f };
+ addShape(m_sdfs.size() - 1, variables, 3);
+ }
+
+ // Wall left
+ {
+ float variables[8]{ 0 - 5, 20, 5.0f, 30.0f, 0.0f };
+ addShape(m_sdfs.size() - 1, variables, 3);
+ }
+ }
+
+ vec3 getColor(const char* path, int x, int y)
+ {
+ // Load the image
+ int width, height, channels;
+ unsigned char* img = wstbi_load(path, &width, &height, &channels, 0);
+
+ if (img == nullptr)
+ {
+ std::cerr << "Error: could not load image." << std::endl;
+ return vec3();
+ }
+
+ if (x < 0)
+ {
+ x = 0;
+ }
+ else if (x >= width)
+ {
+ x = width - 1;
+ }
+
+ if (y < 0)
+ {
+ y = 0;
+ }
+ else if (y >= height)
+ {
+ y = height - 1;
+ }
+
+ // Calculate the index of the pixel in the image data
+ int index = (y * width + x) * channels;
+
+ if (index < 0 || index >= width * height * channels)
+ {
+ return vec3();
+ }
+
+ // Get the color values
+ unsigned char r = img[index];
+ unsigned char g = img[index + 1];
+ unsigned char b = img[index + 2];
+ unsigned char a = (channels == 4) ? img[index + 3] : 255; // Alpha channel (if present)
+
+ // Free the image memory
+ wstbi_image_free(img);
+
+ return vec3(
+ static_cast(r) / 255.0f,
+ static_cast(g) / 255.0f,
+ static_cast(b) / 255.0f);
+ }
+
+ void onUpdate(float delta) override
+ {
+ // Get colors
+ if (Input::GetKeyDown(Input::P))
+ {
+ auto components = m_ecs.getComponentArray();
+
+ // Result string
+ std::string result;
+ result.reserve(components->getSize());
+ for (size_t i = 0; i < components->getSize(); i++)
+ {
+ RigidBody2D& rb = components->getDataAtIdx(i);
+ Transform& t = m_ecs.getComponent(rb.Owner);
+
+ int x = floor(t.position.x);
+ int y = floor(30 - t.position.y);
+
+ vec3 color = getColor(imagePath.c_str(), x * 10, y * 10);
+ int id = m_sdfRenderSystem2D.findClosestColorInPalette(color);
+
+ result += std::to_string(id) + "-";
+ }
+
+ saveToFile(filePath.c_str(), result);
+ std::cout << "Image saved" << std::endl;
+ }
+ }
+};
diff --git a/examples/sample-scenes/include/Lines.h b/examples/sample-scenes/include/Lines.h
new file mode 100644
index 0000000..936cb77
--- /dev/null
+++ b/examples/sample-scenes/include/Lines.h
@@ -0,0 +1,111 @@
+#pragma once
+
+#include
+
+using namespace WeirdEngine;
+class LinesScene : public Scene
+{
+private:
+ Texture *m_colorTextureCopy;
+
+ RenderPlane *m_renderPlane;
+ Shader *m_lineShader;
+
+ RenderTarget *m_lineRender;
+ Texture *m_lineTexture;
+
+ Shader *m_combinationShader;
+
+ Entity m_monkey;
+
+ void onCreate() override
+ {
+ m_renderPlane = new RenderPlane();
+ m_colorTextureCopy = new Texture(Screen::rWidth, Screen::rHeight, Texture::TextureType::Data);
+ m_lineShader = new Shader(SHADERS_PATH "renderPlane.vert", ASSETS_PATH "lines/lines.frag");
+
+ m_lineRender = new RenderTarget(false);
+ m_lineTexture = new Texture(Screen::rWidth, Screen::rHeight, Texture::TextureType::Data);
+ m_lineRender->bindColorTextureToFrameBuffer(*m_lineTexture);
+
+ m_combinationShader = new Shader(SHADERS_PATH "renderPlane.vert", ASSETS_PATH "lines/combination.frag");
+ }
+
+ // Inherited via Scene
+ void onStart() override
+ {
+ m_renderMode = RenderMode::RayMarching3D;
+ m_debugFly = false;
+
+ {
+ Entity entity = m_ecs.createEntity();
+ Transform &t = m_ecs.addComponent(entity);
+ t.position = vec3(0, 0, 0);
+
+ // MeshRenderer &mr = m_ecs.addComponent(entity);
+
+ // auto id = m_resourceManager.getMeshId(ASSETS_PATH "monkey/demo.gltf", entity, true);
+ // mr.mesh = id;
+
+ auto& sdf = m_ecs.addComponent(entity);
+ sdf.materialId = 0;
+
+ m_monkey = entity;
+ }
+ }
+
+ void onUpdate(float delta) override
+ {
+ Transform &cameraTransform = m_ecs.getComponent(m_mainCamera);
+ cameraTransform.position.y = 5.0f;
+ cameraTransform.position.z -= 10.0f * delta;
+
+ Transform& monkeyTransform = m_ecs.getComponent(m_monkey);
+ monkeyTransform.position = cameraTransform.position;
+ monkeyTransform.position.z -= 5.0f;
+ }
+
+ void onRender(WeirdRenderer::RenderTarget &renderTarget) override
+ {
+ m_lineRender->bind();
+ glClearColor(0, 0, 0, 0); // Set clear color
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear both buffers
+
+ // Copy
+ glCopyImageSubData(
+ renderTarget.getColorAttachment()->ID, GL_TEXTURE_2D, 0, 0, 0, 0, // 2 = scene texture
+ m_colorTextureCopy->ID, GL_TEXTURE_2D, 0, 0, 0, 0,
+ Screen::rWidth, Screen::rHeight, 1);
+
+ // --- Line detection ---
+ m_lineShader->use();
+
+ m_lineShader->setUniform("t_sceneDepth", 0);
+ renderTarget.getDepthAttachment()->bind(0);
+
+ m_lineShader->setUniform("u_pixelSize", vec2(1.0f / Screen::rWidth, 1.0f / Screen::rHeight));
+
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ m_renderPlane->draw(*m_lineShader);
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+
+ // --- Final draw ---
+ renderTarget.bind();
+
+ m_combinationShader->use();
+
+ m_combinationShader->setUniform("t_scene", 0);
+ m_colorTextureCopy->bind(0);
+
+ m_combinationShader->setUniform("t_lines", 1);
+ m_lineTexture->bind(1);
+
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ m_renderPlane->draw(*m_combinationShader);
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ }
+};
\ No newline at end of file
diff --git a/examples/sample-scenes/include/MouseCollisionScene.h b/examples/sample-scenes/include/MouseCollisionScene.h
new file mode 100644
index 0000000..a02d449
--- /dev/null
+++ b/examples/sample-scenes/include/MouseCollisionScene.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include
+
+using namespace WeirdEngine;
+class MouseCollisionScene : public Scene
+{
+public:
+ MouseCollisionScene()
+ : Scene() {
+ };
+
+private:
+ Entity m_cursorShape;
+
+ // Inherited via Scene
+ void onStart() override
+ {
+ for (size_t i = 0; i < 600; i++)
+ {
+
+ float y = (int)(i / 20);
+ float x = 5 + (i % 20) + sin(y);
+
+ int material = 4 + (i % 12);
+
+ float z = 0;
+
+ Entity entity = m_ecs.createEntity();
+ Transform& t = m_ecs.addComponent(entity);
+ t.position = vec3(x + 0.5f, y + 0.5f, z);
+
+ if (i < 100)
+ {
+ }
+
+ SDFRenderer& sdfRenderer = m_ecs.addComponent(entity);
+ sdfRenderer.materialId = material;
+
+ RigidBody2D& rb = m_ecs.addComponent(entity);
+ }
+
+ // Floor
+ {
+ float variables[8]{ 0.5f, 1.5f, -1.0f };
+ addShape(0, variables, 3);
+ }
+
+ {
+ float variables[8]{ -15.0f, 50.0f, 5.0f, 5.0f, 2.0f, 10.0f };
+ Entity star = addShape(1, variables, 3);
+
+ m_cursorShape = star;
+ }
+ }
+
+ void onUpdate(float delta) override
+ {
+ // Move wall to mouse
+ {
+ CustomShape& cs = m_ecs.getComponent(m_cursorShape);
+ auto& cameraTransform = m_ecs.getComponent(m_mainCamera);
+ float x = Input::GetMouseX();
+ float y = Input::GetMouseY();
+
+ // Transform mouse coordinates to world space
+ vec2 mousePositionInWorld = ECS::Camera::screenPositionToWorldPosition2D(cameraTransform, vec2(x, y));
+
+ cs.m_parameters[0] = mousePositionInWorld.x;
+ cs.m_parameters[1] = mousePositionInWorld.y;
+ cs.m_isDirty = true;
+ }
+ }
+};
diff --git a/examples/sample-scenes/include/RopeScene.h b/examples/sample-scenes/include/RopeScene.h
new file mode 100644
index 0000000..91c7c54
--- /dev/null
+++ b/examples/sample-scenes/include/RopeScene.h
@@ -0,0 +1,162 @@
+#pragma once
+
+#include
+
+using namespace WeirdEngine;
+// Example scene demonstrating how to create a rope of connected circles using springs.
+class RopeScene : public Scene
+{
+public:
+ RopeScene()
+ : Scene()
+ {
+ }
+
+private:
+ Entity m_star;
+ double m_lastSpawnTime = 0.0;
+
+ void onStart() override
+ {
+ m_debugInput = true;
+
+ // Load fixed-width font for on-screen text
+ loadFont(ENGINE_PATH "/src/weird-renderer/fonts/small.bmp", 4, 5,
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ[]{}abcdefghijklmnopqrstuvwxyz\\/<>0123456789!\" ");
+
+ print("Nice rope dude!");
+
+ constexpr int numBalls = 60;
+ constexpr int rowWidth = 30;
+ constexpr float startY = 20.0f + (numBalls / rowWidth);
+ constexpr float stiffness = 20000000.0f;
+
+ // Create 2D rigid bodies in a rope/grid layout
+ for (int i = 0; i < numBalls; ++i)
+ {
+ float x = static_cast(i % rowWidth);
+ float y = startY - static_cast(i / rowWidth);
+ int material = 4 + (i % 12);
+
+ Entity entity = m_ecs.createEntity();
+
+ auto& t = m_ecs.addComponent(entity);
+ t.position = vec3(x + 0.5f, y + 0.5f, 0.0f);
+
+ auto& sdf = m_ecs.addComponent(entity);
+ sdf.materialId = material;
+
+ m_ecs.addComponent(entity);
+ }
+
+ // Connect balls with springs (down and right)
+ for (int i = 0; i < numBalls; ++i)
+ {
+ if (i + rowWidth < numBalls) // Down
+ {
+ m_simulation2D.addSpring(i, i + rowWidth, stiffness);
+ }
+
+ if ((i + 1) % rowWidth != 0) // Right
+ {
+ m_simulation2D.addSpring(i, i + 1, stiffness);
+ }
+ }
+
+ // Fix top corners
+ if (numBalls >= rowWidth)
+ {
+ m_simulation2D.fix(0);
+ m_simulation2D.fix(rowWidth - 1);
+ }
+
+ // Add base shapes (walls, ground, custom)
+ float vars0[8] = { 1.0f, 0.5f }; // Floor shape
+ addShape(0, vars0, 3);
+
+ float vars1[8] = { 25.0f, 10.0f, 5.0f, 0.5f, 13.0f, 5.0f }; // Custom shape
+ m_star = addShape(1, vars1, 3);
+
+ float vars2[8] = { 30.5f, 3.5f, 30.0f, 3.0f };
+ // addScreenSpaceShape(3, vars2); // UI overlay shape
+
+ float vars3[8] = { 15.0f, 0.0f, 15.0f, 2.0f };
+ addShape(3, vars3, 3);
+ }
+
+ void throwBalls(ECSManager& ecs, Simulation2D& sim)
+ {
+ if (sim.getSimulationTime() <= m_lastSpawnTime + 0.1)
+ {
+ return;
+ }
+
+ constexpr int amount = 10;
+ for (int i = 0; i < amount; ++i)
+ {
+ float y = 60.0f + (1.2f * i);
+
+ Entity entity = ecs.createEntity();
+
+ auto& t = ecs.addComponent(entity);
+ t.position = vec3(0.5f, y + 0.5f, 0.0f);
+
+ auto& sdf = ecs.addComponent(entity);
+ sdf.materialId = 4 + ecs.getComponentArray()->getSize() % 12;
+
+ auto& rb = ecs.addComponent(entity);
+ sim.addForce(rb.simulationId, vec2(20.0f, 0.0f));
+ }
+
+ m_lastSpawnTime = sim.getSimulationTime();
+ }
+
+ void onUpdate(float delta) override
+ {
+ // Animate custom shape over time
+ {
+ auto& cs = m_ecs.getComponent(m_star);
+ cs.m_parameters[4] = static_cast(std::floor(m_simulation2D.getSimulationTime())) % 5 + 2;
+ cs.m_parameters[3] = std::sin(3.1416f * m_simulation2D.getSimulationTime());
+ cs.m_isDirty = true;
+ }
+
+ if (Input::GetKey(Input::E))
+ {
+ throwBalls(m_ecs, m_simulation2D);
+ }
+
+ if (Input::GetKeyDown(Input::M))
+ {
+ auto& cam = m_ecs.getComponent(m_mainCamera);
+ vec2 screen = { Input::GetMouseX(), Input::GetMouseY() };
+ vec2 world = ECS::Camera::screenPositionToWorldPosition2D(cam, screen);
+
+ float vars[8] = { world.x, world.y, 5.0f, 0.5f, 13.0f, 5.0f };
+ addShape(1, vars, 3);
+ }
+
+ if (Input::GetKeyDown(Input::N))
+ {
+ // Duplicate last SDF, add new shape with it
+ m_sdfs.push_back(m_sdfs.back());
+ m_simulation2D.setSDFs(m_sdfs);
+
+ auto& cam = m_ecs.getComponent(m_mainCamera);
+ vec2 screen = { Input::GetMouseX(), Input::GetMouseY() };
+ vec2 world = ECS::Camera::screenPositionToWorldPosition2D(cam, screen);
+
+ float vars[8] = { world.x, world.y, 5.0f, 7.5f, 1.0f };
+ addShape(m_sdfs.size() - 1, vars, 3);
+ }
+
+ if (Input::GetKeyDown(Input::K))
+ {
+ auto components = m_ecs.getComponentArray();
+ int id = components->getSize() - 1;
+
+ m_simulation2D.removeShape(components->getDataAtIdx(id));
+ m_ecs.destroyEntity(components->getDataAtIdx(id).Owner);
+ }
+ }
+};
diff --git a/examples/sample-scenes/include/ShapesCombinations.h b/examples/sample-scenes/include/ShapesCombinations.h
new file mode 100644
index 0000000..ccaee8f
--- /dev/null
+++ b/examples/sample-scenes/include/ShapesCombinations.h
@@ -0,0 +1,140 @@
+#pragma once
+
+#include
+
+#include
+
+using namespace WeirdEngine;
+// Example scene demonstrating how to create a rope of connected circles using springs.
+class ShapeCombinatiosScene : public Scene
+{
+public:
+ ShapeCombinatiosScene()
+ : Scene()
+ {
+ }
+
+
+
+private:
+
+ Entity m_circle;
+ Entity m_circle2 = 0;
+ float m_circleRadioud = 0.0f;
+ vec2 m_initialMousePositionInWorld;
+
+ void onStart() override
+ {
+ m_debugInput = true;
+
+ // Floor shape
+ {
+ float vars0[8] = {0.5f, 2.5f};
+ addShape(CustomShape::SINE, vars0, 2, CombinationType::Addition, true, 0);
+ }
+
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ float range = 20.0f;
+ std::uniform_real_distribution<> distrib(-range, range);
+
+ // Boxes
+ {
+ std::uniform_real_distribution<> distribY(0, 5);
+
+ for (int i = 0; i < 0; ++i)
+ {
+ float x = distrib(gen);
+ float y = -2.0f + distribY(gen);
+
+ float vars2[8] = { x, y, 3.0f, 5.0f, 1.0f, 0.0f }; // Custom shape
+ addShape(CustomShape::BOX, vars2, 4 + i, CombinationType::Addition, true, 1);
+ }
+ }
+
+
+
+ // Circle
+ {
+ float vars[8] = { 0.0f, 7.5f, 5.0f};
+ addShape(CustomShape::CIRCLE, vars, 3, CombinationType::Addition, true, 2);
+ }
+
+ // Subtract star
+ {
+ float vars[8] = { -2.5f, 12.5f, 5.0f, 0.5f, 13.0f, 5.0f };
+ addShape(CustomShape::STAR, vars, 0, CombinationType::Subtraction, true, 2);
+ }
+
+
+ // Cursor circle
+ {
+ float vars2[8] = { 25.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f }; // Custom shape
+ m_circle = addShape(CustomShape::CIRCLE, vars2, 0, CombinationType::Subtraction, true, CustomShape::GLOBAL_GROUP);
+ }
+
+ {
+ float vars2[8] = { 0.0f, 0.0f, 30.0f, 0.0f, 0.0f, 0.0f }; // Custom shape
+ addShape(CustomShape::CIRCLE, vars2, 0, CombinationType::Intersection, true, CustomShape::GLOBAL_GROUP);
+ }
+
+ vec3 camPos = vec3(0.0f, 7.5f, 15.0f);
+ // m_ecs.getComponent(m_mainCamera).position = camPos;
+ m_ecs.getComponent(m_mainCamera).targetPosition = camPos;
+ }
+
+ void onUpdate(float delta) override
+ {
+ auto& cameraTransform = m_ecs.getComponent(m_mainCamera);
+ float x = Input::GetMouseX();
+ float y = Input::GetMouseY();
+
+ // Transform mouse coordinates to world space
+ vec2 mousePositionInWorld = ECS::Camera::screenPositionToWorldPosition2D(cameraTransform, vec2(x, y));
+
+
+
+ if(Input::GetMouseButtonDown(Input::RightClick))
+ {
+ m_initialMousePositionInWorld = mousePositionInWorld;
+ }
+
+ if(Input::GetMouseButton(Input::RightClick))
+ {
+ vec2 v = mousePositionInWorld - m_initialMousePositionInWorld;
+ m_circleRadioud = std::min(10.0f, length(v));
+ }
+ else
+ {
+ m_circleRadioud -= delta * 10.0f * (m_circleRadioud + 1.0f);
+ m_circleRadioud = std::max(0.0f, m_circleRadioud);
+ }
+
+
+ {
+
+ CustomShape& cs = m_ecs.getComponent(m_circle);
+ cs.m_parameters[0] = m_initialMousePositionInWorld.x;
+ cs.m_parameters[1] = m_initialMousePositionInWorld.y;
+ cs.m_parameters[2] = m_circleRadioud;
+
+ cs.m_isDirty = true;
+ }
+
+
+ if (m_circle2)
+ {
+ CustomShape& cs = m_ecs.getComponent(m_circle2);
+ cs.m_parameters[0] = m_initialMousePositionInWorld.x;
+ cs.m_parameters[1] = m_initialMousePositionInWorld.y;
+ cs.m_parameters[2] = std::max(0.0f, m_circleRadioud - 0.1f);
+
+ cs.m_isDirty = true;
+ }
+ }
+
+ // void onCollision(WeirdEngine::CollisionEvent &event) override
+ // {
+ // m_simulation2D.fix(event.bodyB);
+ // }
+};
diff --git a/examples/sample-scenes/include/SpaceScene.h b/examples/sample-scenes/include/SpaceScene.h
new file mode 100644
index 0000000..c6fefbf
--- /dev/null
+++ b/examples/sample-scenes/include/SpaceScene.h
@@ -0,0 +1,85 @@
+#pragma once
+
+#include
+#include
+
+using namespace WeirdEngine;
+class SpaceScene : public Scene
+{
+private:
+ std::vector m_celestialBodies;
+ uint16_t m_current = 0;
+ bool m_lookAtBody = true;
+
+ // Inherited via Scene
+ void onStart() override
+ {
+ // m_debugFly = false;
+
+ m_simulation2D.setGravity(0);
+ m_simulation2D.setDamping(0);
+
+ loadRandomSystem();
+ }
+
+ void loadRandomSystem()
+ {
+
+ std::random_device rd;
+ std::mt19937 gen(rd());
+
+ std::uniform_real_distribution floatDistrib(-1, 1);
+ std::uniform_real_distribution massDistrib(0.1f, 100.0f);
+ std::uniform_int_distribution colorDistrib(2, 15);
+
+ size_t bodyCount = 1000;
+ float r = 0;
+ for (size_t i = 0; i < bodyCount; i++)
+ {
+
+ Entity body = m_ecs.createEntity();
+
+ vec2 pos(floatDistrib(gen), floatDistrib(gen));
+ Transform& t = m_ecs.addComponent(body);
+ t.position = 500.0f * vec3(pos.x, pos.y, 0);
+
+ SDFRenderer& sdfRenderer = m_ecs.addComponent(body);
+ sdfRenderer.materialId = 4 + (i % 3);
+
+ RigidBody2D& rb = m_ecs.addComponent(body);
+ m_simulation2D.setMass(rb.simulationId, 1.0f);
+
+ for (auto b : m_celestialBodies)
+ {
+ m_simulation2D.addGravitationalConstraint(
+ m_ecs.getComponent(body).simulationId,
+ m_ecs.getComponent(b).simulationId,
+ 100.0f);
+ }
+
+ m_simulation2D.addForce(m_ecs.getComponent(body).simulationId, (10.f * vec2(-pos.y, pos.x)) - (10.0f * vec2(pos.x, pos.y)));
+
+ m_celestialBodies.push_back(body);
+ }
+
+ lookAt(m_celestialBodies[0]);
+ }
+
+ void onUpdate(float delta) override
+ {
+ if (Input::GetKeyDown(Input::E))
+ {
+ m_current = (m_current + 1) % m_celestialBodies.size();
+ }
+
+ if (Input::GetKeyDown(Input::F))
+ {
+ m_lookAtBody = !m_lookAtBody;
+ }
+
+ if (m_lookAtBody && m_celestialBodies.size() > 0)
+ {
+ lookAt(m_celestialBodies[m_current]);
+ }
+ }
+};
diff --git a/examples/sample-scenes/include/Text.h b/examples/sample-scenes/include/Text.h
new file mode 100644
index 0000000..fd7b6ee
--- /dev/null
+++ b/examples/sample-scenes/include/Text.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+
+using namespace WeirdEngine;
+class TextScene : public WeirdEngine:: Scene
+{
+
+private:
+
+
+
+ // Inherited via Scene
+ void onStart() override
+ {
+ std::string example("Hello World!");
+
+ print(example);
+ }
+
+ void onUpdate(float delta) override
+ {
+ }
+};
\ No newline at end of file
diff --git a/examples/sample-scenes/include/Water.h b/examples/sample-scenes/include/Water.h
new file mode 100644
index 0000000..c733034
--- /dev/null
+++ b/examples/sample-scenes/include/Water.h
@@ -0,0 +1,403 @@
+#pragma once
+
+#include
+
+using namespace WeirdEngine;
+class WaterScene : public Scene
+{
+private:
+ Shader m_flameShader;
+ Shader m_particlesShader;
+ Shader m_smokeShader;
+ Shader m_litShader;
+ Shader m_heatDistortionShader;
+ Shader m_blurShader;
+ Shader m_bloomShader;
+ Shader m_brightFilterShader;
+ Shader m_backgroundShader;
+
+ Mesh* m_quad = nullptr;
+ Mesh* m_cube = nullptr;
+
+ Texture* m_noiseTexture = nullptr;
+ Texture* m_flameShape = nullptr;
+ Texture* m_sceneTextureBeforeFire = nullptr; // Copy of scene texture for heat effect
+ Texture* m_postProcessTextureFront = nullptr;
+ Texture* m_postProcessTextureBack = nullptr;
+ Texture* m_brightPassTexture = nullptr;
+
+ RenderTarget* m_postProcessRenderFront;
+ RenderTarget* m_postProcessRenderBack;
+ RenderTarget* m_bloomRenderTarget;
+
+ RenderTarget* m_postProcessDoubleBuffer[2];
+
+ RenderPlane m_renderPlane;
+
+ std::vector m_lights;
+
+ void onCreate() override
+ {
+ m_renderMode = RenderMode::Simple3D;
+
+ // Base shaders
+ m_backgroundShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "backgroundGrid.frag");
+ m_litShader = Shader(SHADERS_PATH "default.vert", SHADERS_PATH "lit.frag");
+ m_bloomShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "bloom.frag");
+ m_blurShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "blur.frag");
+ m_brightFilterShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "brightFilter.frag");
+
+ // Custom shaders
+ m_flameShader = Shader(SHADERS_PATH "default.vert", ASSETS_PATH "fire/shaders/flame.frag");
+ m_particlesShader = Shader(ASSETS_PATH "fire/shaders/fireParticles.vert", ASSETS_PATH "fire/shaders/fireParticles.frag");
+ m_smokeShader = Shader(ASSETS_PATH "fire/shaders/smokeParticles.vert", ASSETS_PATH "fire/shaders/smokeParticles.frag");
+ m_heatDistortionShader = Shader(SHADERS_PATH "default.vert", ASSETS_PATH "water/shaders/water.frag");
+
+ m_lights.push_back(
+ Light {
+ 0,
+ glm::vec3(0.0f, 1.0f, 0.0f),
+ 0,
+ glm::vec3(0.0f),
+ glm::vec4(1.0f, 0.95f, 0.9f, 2.0f) });
+
+ // Load meshes
+ // Quad geom
+ {
+ float size = 0.5f;
+ std::vector vertices = {
+ // positions // normals // colors // UVs
+ { { -size, -size, 0.f }, { 0.f, 0.f, 1.f }, { 1.f, 1.f, 1.f }, { 0.f, 0.f } }, // bottom left
+ { { size, -size, 0.f }, { 0.f, 0.f, 1.f }, { 1.f, 1.f, 1.f }, { 1.f, 0.f } }, // bottom right
+ { { size, size, 0.f }, { 0.f, 0.f, 1.f }, { 1.f, 1.f, 1.f }, { 1.f, 1.f } }, // top right
+ { { -size, size, 0.f }, { 0.f, 0.f, 1.f }, { 1.f, 1.f, 1.f }, { 0.f, 1.f } } // top left
+ };
+
+ std::vector indices = {
+ 0, 2, 1, // first triangle
+ 3, 2, 0 // second triangle
+ };
+
+ std::vector textures = {};
+ m_quad = new Mesh(1, vertices, indices, textures);
+ m_quad->m_isBillboard = false;
+ }
+
+ // Cube geom
+ {
+ float size = 0.5f;
+ std::vector vertices = {
+ // positions // normals // colors // UVs
+ // Front face
+ { { -size, -size, size }, { 0.f, 0.f, 1.f }, { 1.f, 1.f, 1.f }, { 0.f, 0.f } },
+ { { size, -size, size }, { 0.f, 0.f, 1.f }, { 1.f, 1.f, 1.f }, { 1.f, 0.f } },
+ { { size, size, size }, { 0.f, 0.f, 1.f }, { 1.f, 1.f, 1.f }, { 1.f, 1.f } },
+ { { -size, size, size }, { 0.f, 0.f, 1.f }, { 1.f, 1.f, 1.f }, { 0.f, 1.f } },
+
+ // Back face
+ { { -size, -size, -size }, { 0.f, 0.f, -1.f }, { 1.f, 1.f, 1.f }, { 1.f, 0.f } },
+ { { size, -size, -size }, { 0.f, 0.f, -1.f }, { 1.f, 1.f, 1.f }, { 0.f, 0.f } },
+ { { size, size, -size }, { 0.f, 0.f, -1.f }, { 1.f, 1.f, 1.f }, { 0.f, 1.f } },
+ { { -size, size, -size }, { 0.f, 0.f, -1.f }, { 1.f, 1.f, 1.f }, { 1.f, 1.f } },
+
+ // Left face
+ { { -size, -size, -size }, { -1.f, 0.f, 0.f }, { 1.f, 1.f, 1.f }, { 0.f, 0.f } },
+ { { -size, -size, size }, { -1.f, 0.f, 0.f }, { 1.f, 1.f, 1.f }, { 1.f, 0.f } },
+ { { -size, size, size }, { -1.f, 0.f, 0.f }, { 1.f, 1.f, 1.f }, { 1.f, 1.f } },
+ { { -size, size, -size }, { -1.f, 0.f, 0.f }, { 1.f, 1.f, 1.f }, { 0.f, 1.f } },
+
+ // Right face
+ { { size, -size, size }, { 1.f, 0.f, 0.f }, { 1.f, 1.f, 1.f }, { 0.f, 0.f } },
+ { { size, -size, -size }, { 1.f, 0.f, 0.f }, { 1.f, 1.f, 1.f }, { 1.f, 0.f } },
+ { { size, size, -size }, { 1.f, 0.f, 0.f }, { 1.f, 1.f, 1.f }, { 1.f, 1.f } },
+ { { size, size, size }, { 1.f, 0.f, 0.f }, { 1.f, 1.f, 1.f }, { 0.f, 1.f } },
+
+ // Top face
+ { { -size, size, size }, { 0.f, 1.f, 0.f }, { 1.f, 1.f, 1.f }, { 0.f, 0.f } },
+ { { size, size, size }, { 0.f, 1.f, 0.f }, { 1.f, 1.f, 1.f }, { 1.f, 0.f } },
+ { { size, size, -size }, { 0.f, 1.f, 0.f }, { 1.f, 1.f, 1.f }, { 1.f, 1.f } },
+ { { -size, size, -size }, { 0.f, 1.f, 0.f }, { 1.f, 1.f, 1.f }, { 0.f, 1.f } },
+
+ // Bottom face
+ { { -size, -size, -size }, { 0.f, -1.f, 0.f }, { 1.f, 1.f, 1.f }, { 0.f, 0.f } },
+ { { size, -size, -size }, { 0.f, -1.f, 0.f }, { 1.f, 1.f, 1.f }, { 1.f, 0.f } },
+ { { size, -size, size }, { 0.f, -1.f, 0.f }, { 1.f, 1.f, 1.f }, { 1.f, 1.f } },
+ { { -size, -size, size }, { 0.f, -1.f, 0.f }, { 1.f, 1.f, 1.f }, { 0.f, 1.f } },
+ };
+
+ std::vector indices = {
+ // Front face
+ 0, 2, 1, 2, 0, 3,
+ // Back face
+ 7, 5, 6, 5, 7, 4,
+ // Left face
+ 11, 10, 9, 9, 8, 11,
+ // Right face
+ 12, 14, 13, 15, 14, 12,
+ // Top face
+ 19, 18, 17, 17, 16, 19,
+ // Bottom face
+ 22, 21, 20, 20, 23, 22
+ };
+
+ std::vector textures = {};
+ m_cube = new Mesh(2, vertices, indices, textures);
+ }
+
+ // Fire textures
+ m_noiseTexture = new Texture(ASSETS_PATH "fire/fire.jpg");
+ m_flameShape = new Texture(ASSETS_PATH "fire/flame.png");
+
+ m_sceneTextureBeforeFire = new Texture(Screen::rWidth, Screen::rHeight, Texture::TextureType::Data);
+ m_postProcessTextureFront = new Texture(Screen::rWidth, Screen::rHeight, Texture::TextureType::Data);
+ m_postProcessTextureBack = new Texture(Screen::rWidth, Screen::rHeight, Texture::TextureType::Data);
+
+ m_postProcessRenderFront = new RenderTarget(false);
+ m_postProcessRenderFront->bindColorTextureToFrameBuffer(*m_postProcessTextureFront);
+
+ m_postProcessRenderBack = new RenderTarget(false);
+ m_postProcessRenderBack->bindColorTextureToFrameBuffer(*m_postProcessTextureBack);
+
+ m_postProcessDoubleBuffer[0] = m_postProcessRenderFront;
+ m_postProcessDoubleBuffer[1] = m_postProcessRenderBack;
+
+ // Bloom Texture and Render Target
+ m_brightPassTexture = new Texture(Screen::rWidth, Screen::rHeight, Texture::TextureType::Data);
+ m_bloomRenderTarget = new RenderTarget(false);
+ m_bloomRenderTarget->bindColorTextureToFrameBuffer(*m_brightPassTexture);
+ }
+
+ void onDestroy() override
+ {
+ m_flameShader.free();
+ m_particlesShader.free();
+ m_smokeShader.free();
+ m_litShader.free();
+ m_heatDistortionShader.free();
+ m_blurShader.free();
+ m_bloomShader.free();
+ m_brightFilterShader.free();
+ m_backgroundShader.free();
+
+ m_quad->free();
+ delete m_quad;
+ m_cube->free();
+ delete m_quad;
+
+ m_noiseTexture->dispose();
+ delete m_noiseTexture;
+ m_flameShape->dispose();
+ delete m_flameShape;
+ m_sceneTextureBeforeFire->dispose();
+ delete m_sceneTextureBeforeFire;
+ m_postProcessTextureFront->dispose();
+ delete m_postProcessTextureFront;
+ m_postProcessTextureBack->dispose();
+ delete m_postProcessTextureBack;
+ m_brightPassTexture->dispose();
+ delete m_brightPassTexture;
+
+ m_postProcessRenderFront->free();
+ delete m_postProcessRenderFront;
+ m_postProcessRenderBack->free();
+ delete m_postProcessRenderBack;
+ m_bloomRenderTarget->free();
+ delete m_bloomRenderTarget;
+
+ m_renderPlane.free();
+ }
+
+ // Inherited via Scene
+ void onStart() override
+ {
+ m_debugFly = true;
+ }
+
+ float m_time = 3.1416f;
+ void onUpdate(float delta) override
+ {
+ if (m_debugFly)
+ {
+ return;
+ }
+
+ if (!Input::GetKey(Input::Space))
+ {
+ static float speed = 0.15f;
+ if (Input::GetKey(Input::R))
+ {
+ m_time -= delta * speed;
+ }
+ else
+ {
+ m_time += delta * speed;
+ }
+ }
+
+ Transform& cameraTransform = m_ecs.getComponent(m_mainCamera);
+
+ static float amplitude = 12.5f;
+
+ cameraTransform.position.y = 2.0f + tan(0.5f * m_time);
+ cameraTransform.position.x = amplitude * sin(m_time);
+ cameraTransform.position.z = amplitude * cos(m_time);
+
+ cameraTransform.rotation = -cameraTransform.position;
+ }
+
+ void renderWater(WeirdRenderer::Camera& camera, float time)
+ {
+ }
+
+ void onRender(WeirdRenderer::RenderTarget& renderTarget) override
+ {
+
+ WeirdRenderer::Camera& sceneCamera = getCamera();
+ float time = getTime();
+
+ glDepthMask(GL_FALSE);
+ m_backgroundShader.use();
+ m_backgroundShader.setUniform("u_camMatrix", sceneCamera.cameraMatrix);
+ float shaderFov = 1.0f / tan(sceneCamera.fov * 0.01745f * 0.5f);
+ m_backgroundShader.setUniform("u_fov", shaderFov);
+
+ m_renderPlane.draw(m_backgroundShader);
+ // glFrontFace(GL_CW); // Clockwise = front face
+ // m_cube->draw(m_backgroundShader, sceneCamera, sceneCamera.position, vec3(0.0f), vec3(100.0f));
+ // glFrontFace(GL_CCW); // Counter-clockwise = front face (default)
+
+ glDepthMask(GL_TRUE);
+
+ GL_CHECK_ERROR();
+
+ // Render stuff
+ m_litShader.use();
+ m_litShader.setUniform("u_time", (float)time);
+ m_litShader.setUniform("u_ambient", 0.025f);
+
+ // Take care of the camera Matrix
+ m_litShader.setUniform("u_camPos", sceneCamera.position);
+ m_litShader.setUniform("u_camMatrix", sceneCamera.cameraMatrix);
+
+ // Pass light rotation
+ glm::vec3 position = m_lights[0].position;
+ m_litShader.setUniform("u_lightPos", position);
+ glm::vec3 direction = m_lights[0].rotation;
+ m_litShader.setUniform("u_directionalLightDir", direction);
+ glm::vec4 color = m_lights[0].color;
+ m_litShader.setUniform("u_lightColor", color);
+
+ // bind current FBO
+ // m_sceneRender->bind(); // TODO: keep rendering to the same fbo. Should pass the render target and the color and depth textures
+
+ // Floor
+ m_cube->draw(m_litShader, sceneCamera, vec3(0, -500.0f + 1.0f, 0), vec3(0), vec3(4, 1000, 4));
+
+ GL_CHECK_ERROR();
+
+ // m_cube->draw(m_litShader, sceneCamera, vec3(0, 0.0f, 0), vec3(0), vec3(0.1f, 2.0f, 0.1f));
+
+ // Heat effect
+
+ // Don't write to depth buffer
+ glDepthMask(GL_FALSE);
+
+ // Copy scene texture // TODO: replace with glCopyTexSubImage which copies from the current read framebuffer attachment to the given image
+ glCopyImageSubData(
+ renderTarget.getColorAttachment()->ID, GL_TEXTURE_2D, 0, 0, 0, 0, // 2 = scene texture
+ m_sceneTextureBeforeFire->ID, GL_TEXTURE_2D, 0, 0, 0, 0,
+ Screen::rWidth, Screen::rHeight, 1);
+
+ // Heat effect shader
+ m_heatDistortionShader.use();
+ m_heatDistortionShader.setUniform("u_camPos", sceneCamera.position);
+ m_heatDistortionShader.setUniform("u_camMatrix", sceneCamera.cameraMatrix);
+
+ // Takes copy texture
+ m_heatDistortionShader.setUniform("t_texture", 0);
+ m_sceneTextureBeforeFire->bind(0);
+ // Noise texture
+ m_heatDistortionShader.setUniform("t_noise", 1);
+ m_noiseTexture->bind(1);
+ // Flame texture
+ m_heatDistortionShader.setUniform("t_flameShape", 2);
+ m_flameShape->bind(2);
+
+ GL_CHECK_ERROR();
+
+ // Time to animate effect
+ m_heatDistortionShader.setUniform("u_time", (float)time);
+ // Screen resolution to calculate screen uvs
+ m_heatDistortionShader.setUniform("u_resolution", glm::vec2(Screen::rWidth, Screen::rHeight));
+
+ // Render quad
+ m_quad->draw(m_heatDistortionShader, sceneCamera, vec3(0), vec3(-3.14f / 2.0f, 0, 0), vec3(1000));
+
+ // Write to depth buffer
+ glDepthMask(GL_TRUE);
+
+ // Fire
+ renderWater(sceneCamera, time);
+
+ if (Input::GetKey(Input::P))
+ {
+ return;
+ }
+
+ // Post processing
+ m_bloomRenderTarget->bind();
+ m_brightFilterShader.use();
+ m_brightFilterShader.setUniform("t_colorTexture", 0);
+ renderTarget.getColorAttachment()->bind(0);
+
+ m_renderPlane.draw(m_brightFilterShader);
+
+ m_blurShader.use();
+ m_blurShader.setUniform("t_colorTexture", 0);
+
+ bool horizontal = true;
+ static int amount = 10;
+
+ for (unsigned int i = 0; i < amount; i++)
+ {
+ m_postProcessDoubleBuffer[horizontal]->bind();
+
+ m_blurShader.setUniform("u_horizontal", horizontal);
+ if (i == 0)
+ {
+ m_brightPassTexture->bind(0);
+ }
+ else
+ {
+ m_postProcessDoubleBuffer[!horizontal]->getColorAttachment()->bind(0);
+ }
+
+ m_renderPlane.draw(m_blurShader);
+
+ horizontal = !horizontal;
+ }
+
+ // bind a different FBO
+ renderTarget.bind(); // bind to fbo 0
+
+ glDisable(GL_DEPTH_TEST);
+
+ // Use scene texture and a shader to apply pp
+ m_bloomShader.use();
+ m_bloomShader.setUniform("t_sceneTexture", 0);
+ renderTarget.getColorAttachment()->bind(0);
+
+ m_bloomShader.setUniform("t_blurTexture", 1);
+ RenderTarget* finalTarget = m_postProcessDoubleBuffer[!horizontal];
+ finalTarget->getColorAttachment()->bind(1);
+
+ if (Input::GetKey(Input::B))
+ {
+ finalTarget->getColorAttachment()->bind(0);
+ }
+
+ m_bloomShader.setUniform("u_pixelOffset", vec2(0.5f / Screen::rWidth, 0.5f / Screen::rHeight));
+
+ m_renderPlane.draw(m_bloomShader);
+ }
+};
diff --git a/examples/sample-scenes/src/main.cpp b/examples/sample-scenes/src/main.cpp
new file mode 100644
index 0000000..04f607a
--- /dev/null
+++ b/examples/sample-scenes/src/main.cpp
@@ -0,0 +1,41 @@
+
+#include
+
+#include
+
+#include "CollisionHandling.h"
+#include "ApparentCircularMotionScene.h"
+#include "Classic.h"
+#include "DestroyScene.h"
+#include "Fire.h"
+#include "FireworksScene.h"
+#include "ImageScene.h"
+#include "Lines.h"
+#include "MouseCollisionScene.h"
+#include "RopeScene.h"
+#include "Text.h"
+#include "Water.h"
+#include "ShapesCombinations.h"
+
+int main()
+{
+ SceneManager &sceneManager = SceneManager::getInstance();
+ sceneManager.registerScene("shapes");
+ sceneManager.registerScene("rope");
+ sceneManager.registerScene("cursor-collision");
+ sceneManager.registerScene("fire");
+ sceneManager.registerScene("lines");
+
+ // sceneManager.registerScene("collision-handling");
+ // sceneManager.registerScene("water");
+ // sceneManager.registerScene("fireRayMarching");
+ // sceneManager.registerScene("classic");
+ // sceneManager.registerScene("text");
+ // sceneManager.registerScene("empty");
+ // sceneManager.registerScene("image");
+ // sceneManager.registerScene("fireworks");
+ // sceneManager.registerScene("circle");
+ // sceneManager.registerScene("space");
+
+ start(sceneManager);
+}
\ No newline at end of file
diff --git a/include/weird-engine/Scene.h b/include/weird-engine/Scene.h
index 941b16b..0975044 100644
--- a/include/weird-engine/Scene.h
+++ b/include/weird-engine/Scene.h
@@ -64,7 +64,7 @@ namespace WeirdEngine
std::vector> m_sdfs;
- Entity addShape(ShapeId shapeId, float* variables, CombinationType combination = CombinationType::Addition, bool hasCollision = true, int group = 0);
+ Entity addShape(ShapeId shapeId, float* variables, uint16_t material, CombinationType combination = CombinationType::Addition, bool hasCollision = true, int group = 0);
void lookAt(Entity entity);
diff --git a/include/weird-engine/ecs/Components/CustomShape.h b/include/weird-engine/ecs/Components/CustomShape.h
index 48f3d2e..8004579 100644
--- a/include/weird-engine/ecs/Components/CustomShape.h
+++ b/include/weird-engine/ecs/Components/CustomShape.h
@@ -25,6 +25,7 @@ namespace WeirdEngine
bool m_screenSpace;
bool m_hasCollision;
uint16_t m_groupId;
+ uint16_t m_material;
CustomShape() : m_distanceFieldId(0), m_isDirty(true), m_screenSpace(false)
{
diff --git a/include/weird-engine/ecs/Systems/PlayerMovementSystem.h b/include/weird-engine/ecs/Systems/PlayerMovementSystem.h
index 7004eef..33937c6 100644
--- a/include/weird-engine/ecs/Systems/PlayerMovementSystem.h
+++ b/include/weird-engine/ecs/Systems/PlayerMovementSystem.h
@@ -130,9 +130,9 @@ namespace WeirdEngine
targetPosition += flyComponent.scrollSpeed * flyComponent.speed * vec3(travel.x / abs(t.position.z), travel.y / abs(t.position.z), 0);
}
- if (targetPosition.z < 20.0f)
+ if (targetPosition.z < 5.0f)
{
- targetPosition.z = 20.0f;
+ targetPosition.z = 5.0f;
}
if (targetPosition.y < 0.1f)
diff --git a/include/weird-renderer/Renderer.h b/include/weird-renderer/Renderer.h
index 0cc458d..c0cc5ec 100644
--- a/include/weird-renderer/Renderer.h
+++ b/include/weird-renderer/Renderer.h
@@ -42,7 +42,6 @@ namespace WeirdEngine
Renderer(const unsigned int width, const unsigned int height);
~Renderer();
void render(Scene& scene, const double time);
- bool checkWindowClosed() const;
void setWindowTitle(const char* name);
SDL_Window* getWindow();
@@ -52,15 +51,21 @@ namespace WeirdEngine
SDL_Window* m_window;
unsigned int m_windowWidth, m_windowHeight;
+ float m_distanceSampleScale;
float m_renderScale;
+ unsigned int m_distanceSampleWidth, m_distanceSampleHeight;
unsigned int m_renderWidth, m_renderHeight;
bool m_vSyncEnabled;
Shader m_geometryShaderProgram;
Shader m_instancedGeometryShaderProgram;
- Shader m_2DsdfShaderProgram;
- Shader m_postProcessShaderProgram;
+ Shader m_2DDistanceShader;
+ Shader m_2DMaterialColorShader;
+ Shader m_2DMaterialBlendShader;
+ Shader m_2DGridShader;
+ Shader m_2DLightingShader;
+ Shader m_postProcessingShader;
Shader m_3DsdfShaderProgram;
Shader m_combineScenesShaderProgram;
Shader m_outputShaderProgram;
@@ -69,7 +74,9 @@ namespace WeirdEngine
RenderTarget m_3DSceneRender;
RenderTarget m_2DSceneRender;
+ RenderTarget m_2DColorRender;
RenderTarget m_2DPostProcessRender;
+ RenderTarget m_2DBackgroundRender;
RenderTarget m_combinationRender;
RenderTarget m_outputResolutionRender;
@@ -81,20 +88,50 @@ namespace WeirdEngine
Texture m_geometryTexture;
Texture m_geometryDepthTexture;
Texture m_3DSceneTexture;
- Texture m_3DDepthSceneTexture;
+ Texture m_3DDepthSceneTexture;
Texture m_distanceTexture;
+ Texture m_2dColorTexture;
+
+
+ Texture m_postProcessTextureFront;
+ Texture m_postProcessTextureBack;
+ RenderTarget m_postProcessRenderFront;
+ RenderTarget m_postProcessRenderBack;
+ RenderTarget *m_postProcessDoubleBuffer[2];
+
Texture m_lit2DSceneTexture;
+ Texture m_2DBackgroundTexture;
Texture m_combineResultTexture;
WeirdRenderer::Dot2D* m_2DData = nullptr;
uint32_t m_2DDataSize = 0;
- void renderFire(Scene& scene, Camera& camera, float time);
- void renderGeometry(Scene& scene, Camera& camera);
+ uint32_t m_materialBlendIterations;
+
+
void output(Scene& scene, Texture& texture);
+
+ glm::vec3 m_colorPalette[16] = {
+ vec3(0.025f, 0.025f, 0.05f), // Black
+ vec3(1.0f, 1.0f, 1.0f), // White
+ vec3(0.484f, 0.484f, 0.584f), // Dark Gray
+ vec3(0.752f, 0.762f, 0.74f), // Light Gray
+ vec3(.8f, 0.1f, 0.1f), // Red
+ vec3(0.1f, .95f, 0.1f), // Green
+ vec3(0.15f, 0.25f, .85f), // Blue
+ vec3(1.0f, .9f, 0.2f), // Yellow
+ vec3(.95f, 0.4f, 0.1f), // Orange
+ vec3(0.5f, 0.0f, 1.0f), // Purple
+ vec3(0.0f, .9f, .9f), // Cyan
+ vec3(1.0f, 0.3f, .6f), // Magenta
+ vec3(0.5f, 1.0f, 0.5f), // Light Green
+ vec3(1.0f, 0.5f, 0.5f), // Pink
+ vec3(0.5f, 0.5f, 1.0f), // Light Blue
+ vec3(0.4f, 0.25f, 0.1f) // Brown
+ };
};
diff --git a/src/weird-engine/Scene.cpp b/src/weird-engine/Scene.cpp
index 7729e80..e81e811 100644
--- a/src/weird-engine/Scene.cpp
+++ b/src/weird-engine/Scene.cpp
@@ -103,9 +103,9 @@ namespace WeirdEngine
void Scene::updateCustomShapesShader(WeirdRenderer::Shader &shader)
{
- auto sdfBalls = m_ecs.getComponentManager()->getComponentArray();
+ const auto sdfBalls = m_ecs.getComponentManager()->getComponentArray();
int32_t ballsCount = sdfBalls->getSize();
- auto componentArray = m_ecs.getComponentManager()->getComponentArray();
+ const auto componentArray = m_ecs.getComponentManager()->getComponentArray();
shader.setUniform("u_customShapeCount", componentArray->getSize());
if (!m_sdfRenderSystem2D.shaderNeedsUpdate())
@@ -117,7 +117,7 @@ namespace WeirdEngine
std::string str = shader.getFragmentCode();
- std::string toReplace("/*ADD_SHAPES_HERE*/");
+ const std::string toReplace("/*ADD_SHAPES_HERE*/");
std::ostringstream oss;
@@ -133,10 +133,10 @@ namespace WeirdEngine
for (size_t i = 0; i < componentArray->getSize(); i++)
{
// Get shape
- auto &shape = componentArray->getDataAtIdx(i);
+ const auto &shape = componentArray->getDataAtIdx(i);
// Get group
- int group = shape.m_groupId;
+ const int group = shape.m_groupId;
// Start new group if necessary
if(group != currentGroup)
@@ -144,8 +144,7 @@ namespace WeirdEngine
// If this is not the first group, combine current group distance with global minDistance
if(currentGroup != -1)
{
- oss << "if(minDist >"<< groupDistanceVariable <<"){ minDist = "<< groupDistanceVariable <<";\n";
- oss << "col = getMaterial(p," << 3 << ");}\n";
+ oss << "if(minDist >"<< groupDistanceVariable <<"){ minDist = "<< groupDistanceVariable <<";}\n";
}
// Next group
@@ -181,8 +180,8 @@ namespace WeirdEngine
// Shape distance calculation
oss << "float dist = " << fragmentCode << ";" << std::endl;
- // Scale negative distances
- oss << "dist = dist > 0 ? dist : 0.1 * dist;" << std::endl;
+
+
// Apply globalEffect logic
oss << "float currentMinDistance = " << (globalEffect ? "minDist" : groupDistanceVariable) << ";" << std::endl;
@@ -193,6 +192,7 @@ namespace WeirdEngine
case CombinationType::Addition:
{
oss << "currentMinDistance = min(currentMinDistance, dist);\n";
+ oss << "finalMaterialId = dist <= min(minDist, currentMinDistance) ? " << shape.m_material << ": finalMaterialId;" << std::endl;
break;
}
case CombinationType::Subtraction:
@@ -208,6 +208,7 @@ namespace WeirdEngine
case CombinationType::SmoothAddition:
{
oss << "currentMinDistance = fOpUnionSoft(currentMinDistance, dist, 1.0);\n";
+ oss << "finalMaterialId = dist <= min(minDist, currentMinDistance) ? " << shape.m_material << ": finalMaterialId;" << std::endl;
break;
}
default:
@@ -222,10 +223,14 @@ namespace WeirdEngine
// Combine last group
if (componentArray->getSize() > 0)
{
- oss << "if(minDist >" << groupDistanceVariable << "){ minDist = " << groupDistanceVariable << ";\n";
- oss << "col = getMaterial(p," << 3 << ");}\n";
+ oss << "if(minDist >" << groupDistanceVariable << "){ minDist = " << groupDistanceVariable << ";}\n";
}
+ // Scale negative distances
+ oss << "minDist = minDist > 0 ? minDist : 0.1 * minDist;" << std::endl;
+
+ // oss << "col.x = minDist; col.y = 5;" << std::endl;
+
// oss << "minDist -= 1.5;\n";
// Get string
@@ -245,11 +250,18 @@ namespace WeirdEngine
// Set new source code and recompile shader
shader.setFragmentCode(str);
+
+ // TODO: only debug
+ std::ofstream outFile("generated_shader.frag");
+ if (outFile.is_open()) {
+ outFile << str;
+ outFile.close();
+ }
}
void Scene::updateRayMarchingShader(WeirdRenderer::Shader &shader)
{
- m_sdfRenderSystem2D.updatePalette(shader);
+ // m_sdfRenderSystem2D.updatePalette(shader);
updateCustomShapesShader(shader);
}
@@ -314,7 +326,7 @@ namespace WeirdEngine
return m_renderMode;
}
- Entity Scene::addShape(ShapeId shapeId, float* variables, CombinationType combination, bool hasCollision, int group)
+ Entity Scene::addShape(ShapeId shapeId, float* variables, uint16_t material, CombinationType combination, bool hasCollision, int group)
{
Entity entity = m_ecs.createEntity();
CustomShape &shape = m_ecs.addComponent(entity);
@@ -322,6 +334,7 @@ namespace WeirdEngine
shape.m_combination = combination;
shape.m_hasCollision = hasCollision;
shape.m_groupId = group;
+ shape.m_material = material;
std::copy(variables, variables + 8, shape.m_parameters);
// CustomShape shape(shapeId, variables); // check old constructor for references
diff --git a/src/weird-physics/Simulation2D.cpp b/src/weird-physics/Simulation2D.cpp
index 5c1178c..ec00749 100644
--- a/src/weird-physics/Simulation2D.cpp
+++ b/src/weird-physics/Simulation2D.cpp
@@ -531,6 +531,7 @@ namespace WeirdEngine
float d = map(p);
if (d < m_radious)
{
+
float penetration = (m_radious - d);
// Collision normal calculation
@@ -541,25 +542,28 @@ namespace WeirdEngine
vec2 normal = vec2(d - d1, d - d2);
normal = normalize(normal);
- // Position
- p += penetration * normal;
+ if (map(p - (m_radious * normal)) <= EPSILON) // Bad solution?
+ {
+ // Position
+ p += penetration * normal;
- // Impulse
- float restitution = 0.5f;
- vec2 vRel = -m_velocities[i];
- float velocityAlongNormal = glm::dot(normal, vRel);
- float impulseMagnitude = -(1 + restitution) * velocityAlongNormal; // * m_mass[i]; -> cancels out later
- vec2 impulse = impulseMagnitude * normal;
+ // Impulse
+ float restitution = 0.5f;
+ vec2 vRel = -m_velocities[i];
+ float velocityAlongNormal = glm::dot(normal, vRel);
+ float impulseMagnitude = -(1 + restitution) * velocityAlongNormal; // * m_mass[i]; -> cancels out later
+ vec2 impulse = impulseMagnitude * normal;
- // m_velocities[i] -= impulse; // * m_invMass[i]
+ // m_velocities[i] -= impulse; // * m_invMass[i]
- // Penalty
- vec2 v = penetration * normal;
- vec2 force = m_mass[i] * m_push * v;
+ // Penalty
+ vec2 v = penetration * normal;
+ vec2 force = m_mass[i] * m_push * v;
- // force -= (10000.0f * m_damping * m_velocities[i]); // Drag ???
+ // force -= (10000.0f * m_damping * m_velocities[i]); // Drag ???
- m_forces[i] += force;
+ m_forces[i] += force;
+ }
}
// Old walls
diff --git a/src/weird-renderer/Renderer.cpp b/src/weird-renderer/Renderer.cpp
index 037e8f0..ce24514 100644
--- a/src/weird-renderer/Renderer.cpp
+++ b/src/weird-renderer/Renderer.cpp
@@ -81,10 +81,14 @@ namespace WeirdEngine
: m_initializer(width, height, m_window)
, m_windowWidth(width)
, m_windowHeight(height)
+ , m_distanceSampleScale(1.0f)
+ , m_distanceSampleWidth(width * m_distanceSampleScale)
+ , m_distanceSampleHeight(height * m_distanceSampleScale)
, m_renderScale(1.0f)
- , m_renderWidth(width* m_renderScale)
- , m_renderHeight(height* m_renderScale)
+ , m_renderWidth(width * m_renderScale)
+ , m_renderHeight(height * m_renderScale)
, m_vSyncEnabled(true)
+ , m_materialBlendIterations(2)
{
Screen::width = m_windowWidth;
Screen::height = m_windowHeight;
@@ -98,9 +102,17 @@ namespace WeirdEngine
m_3DsdfShaderProgram = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "raymarching.frag");
- m_2DsdfShaderProgram = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "raymarching2d.frag");
+ m_2DDistanceShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "2DSDFDistanceShader.frag");
- m_postProcessShaderProgram = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "postProcess2d.frag");
+ m_2DMaterialColorShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "2DMaterialColorShader.frag");
+
+ m_2DMaterialBlendShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "2DMaterialBlendShader.frag");
+
+ m_2DLightingShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "2DLightingShader.frag");
+
+ m_2DGridShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "2DBackground.frag");
+
+ m_postProcessingShader = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "PostProcessShader.frag");
m_combineScenesShaderProgram = Shader(SHADERS_PATH "renderPlane.vert", SHADERS_PATH "combineScenes.frag");
@@ -122,14 +134,33 @@ namespace WeirdEngine
m_3DSceneRender.bindDepthTextureToFrameBuffer(m_3DDepthSceneTexture);
- m_distanceTexture = Texture(m_renderWidth, m_renderHeight, Texture::TextureType::Data);
+ m_distanceTexture = Texture(m_distanceSampleWidth, m_distanceSampleHeight, Texture::TextureType::Data);
m_2DSceneRender = RenderTarget(false);
m_2DSceneRender.bindColorTextureToFrameBuffer(m_distanceTexture);
- m_lit2DSceneTexture = Texture(m_renderWidth, m_renderHeight, Texture::TextureType::Data);
+ m_2dColorTexture = Texture(m_renderWidth, m_renderHeight, Texture::TextureType::Data);
+ m_2DColorRender = RenderTarget(false);
+ m_2DColorRender.bindColorTextureToFrameBuffer(m_2dColorTexture);
+
+ m_postProcessTextureFront = Texture(m_renderWidth, m_renderHeight, Texture::TextureType::Data);
+ m_postProcessRenderFront = RenderTarget(false);
+ m_postProcessRenderFront.bindColorTextureToFrameBuffer(m_postProcessTextureFront);
+
+ m_postProcessTextureBack = Texture(m_renderWidth, m_renderHeight, Texture::TextureType::Data);
+ m_postProcessRenderBack = RenderTarget(false);
+ m_postProcessRenderBack.bindColorTextureToFrameBuffer(m_postProcessTextureBack);
+
+ m_postProcessDoubleBuffer[0] = &m_postProcessRenderFront;
+ m_postProcessDoubleBuffer[1] = &m_postProcessRenderBack;
+
+ m_lit2DSceneTexture = Texture(m_renderWidth, m_renderHeight, m_renderScale <= 0.5f ? Texture::TextureType::RetroColor : Texture::TextureType::Data);
m_2DPostProcessRender = RenderTarget(false);
m_2DPostProcessRender.bindColorTextureToFrameBuffer(m_lit2DSceneTexture);
+ m_2DBackgroundTexture = Texture(m_renderWidth, m_renderHeight, Texture::TextureType::Data);
+ m_2DBackgroundRender = RenderTarget(false);
+ m_2DBackgroundRender.bindColorTextureToFrameBuffer(m_2DBackgroundTexture);
+
m_combineResultTexture = Texture(m_renderWidth, m_renderHeight, Texture::TextureType::Data);
m_combinationRender = RenderTarget(false);
m_combinationRender.bindColorTextureToFrameBuffer(m_combineResultTexture);
@@ -150,8 +181,8 @@ namespace WeirdEngine
// Delete all the objects we've created
m_geometryShaderProgram.free();
m_instancedGeometryShaderProgram.free();
- m_2DsdfShaderProgram.free();
- m_postProcessShaderProgram.free();
+ m_2DDistanceShader.free();
+ m_2DLightingShader.free();
m_3DsdfShaderProgram.free();
m_combineScenesShaderProgram.free();
m_outputShaderProgram.free();
@@ -210,53 +241,134 @@ namespace WeirdEngine
if (enable2D)
{
{
+ glViewport(0, 0, m_distanceSampleWidth, m_distanceSampleHeight);
+
// Bind the framebuffer you want to render to
m_2DSceneRender.bind();
// Draw ray marching stuff
- m_2DsdfShaderProgram.use();
+ m_2DDistanceShader.use();
- scene.updateRayMarchingShader(m_2DsdfShaderProgram);
+ scene.updateRayMarchingShader(m_2DDistanceShader);
// Set uniforms
- m_2DsdfShaderProgram.setUniform("u_camMatrix", sceneCamera.view);
- m_2DsdfShaderProgram.setUniform("u_time", scene.getTime());
- m_2DsdfShaderProgram.setUniform("u_resolution", glm::vec2(m_renderWidth, m_renderHeight));
+ m_2DDistanceShader.setUniform("u_camMatrix", sceneCamera.view);
+ m_2DDistanceShader.setUniform("u_time", scene.getTime());
+ m_2DDistanceShader.setUniform("u_resolution", glm::vec2( m_distanceSampleWidth, m_distanceSampleHeight));
- m_2DsdfShaderProgram.setUniform("u_blendIterations", 1);
+ m_2DDistanceShader.setUniform("u_blendIterations", 1);
- m_2DsdfShaderProgram.setUniform("t_colorTexture", 0);
+ m_2DDistanceShader.setUniform("t_colorTexture", 0);
m_distanceTexture.bind(0);
// Shape data
scene.get2DShapesData(m_2DData, m_2DDataSize);
- m_2DsdfShaderProgram.setUniform("u_loadedObjects", (int)m_2DDataSize);
+ m_2DDistanceShader.setUniform("u_loadedObjects", (int)m_2DDataSize);
- m_2DsdfShaderProgram.setUniform("t_shapeBuffer", 1);
+ m_2DDistanceShader.setUniform("t_shapeBuffer", 1);
m_shapes2D.uploadData(m_2DData, m_2DDataSize);
m_shapes2D.bind(1);
- m_renderPlane.draw(m_2DsdfShaderProgram);
+ m_renderPlane.draw(m_2DDistanceShader);
m_distanceTexture.unbind();
m_shapes2D.unbind();
}
- // 2D Lighting
+ glViewport(0, 0, m_renderWidth, m_renderHeight);
+
{
- m_2DPostProcessRender.bind();
+ // Bind the framebuffer you want to render to
+ m_2DColorRender.bind();
+
+ // Draw ray marching stuff
+ m_2DMaterialColorShader.use();
- m_postProcessShaderProgram.use();
- m_postProcessShaderProgram.setUniform("u_time", scene.getTime());
- m_postProcessShaderProgram.setUniform("u_resolution", glm::vec2(m_renderWidth, m_renderHeight));
+ // Get materials ?
+ // scene.updateRayMarchingShader(m_2DcolorShaderProgram);
- GLuint u_colorTextureLocation = glGetUniformLocation(m_postProcessShaderProgram.ID, "t_colorTexture");
- glUniform1i(u_colorTextureLocation, 0);
+ // Set uniforms
+ m_2DMaterialColorShader.setUniform("u_camMatrix", sceneCamera.view);
+ m_2DMaterialColorShader.setUniform("u_time", scene.getTime());
+ m_2DMaterialColorShader.setUniform("u_resolution", glm::vec2(m_renderWidth, m_renderHeight));
+ m_2DMaterialColorShader.setUniform("u_staticColors", m_colorPalette, 16);
+ m_2DMaterialColorShader.setUniform("t_materialDataTexture", 0);
m_distanceTexture.bind(0);
- m_renderPlane.draw(m_postProcessShaderProgram);
+ m_2DMaterialColorShader.setUniform("t_currentColorTexture", 1);
+ m_postProcessDoubleBuffer[0]->getColorAttachment()->bind(1);
+
+
+ m_renderPlane.draw(m_2DMaterialColorShader);
+
m_distanceTexture.unbind();
+ m_shapes2D.unbind();
+ }
+
+ static bool horizontal = true;
+ {
+ m_2DMaterialBlendShader.use();
+ m_2DMaterialBlendShader.setUniform("t_colorTexture", 0);
+ m_2DMaterialBlendShader.setUniform("u_time", scene.getTime());
+
+ for (unsigned int i = 0; i < m_materialBlendIterations; i++)
+ {
+ m_postProcessDoubleBuffer[horizontal]->bind();
+
+ m_2DMaterialBlendShader.setUniform("u_horizontal", horizontal);
+ if (i == 0)
+ {
+ m_2dColorTexture.bind(0);
+ }
+ else
+ {
+ m_postProcessDoubleBuffer[!horizontal]->getColorAttachment()->bind(0);
+ }
+
+ m_renderPlane.draw(m_2DMaterialBlendShader);
+
+ horizontal = !horizontal;
+ }
+ }
+
+ {
+ m_2DBackgroundRender.bind();
+
+ m_2DGridShader.use();
+ m_2DGridShader.setUniform("u_camMatrix", sceneCamera.view);
+ m_2DGridShader.setUniform("u_time", scene.getTime());
+ m_2DGridShader.setUniform("u_resolution", glm::vec2(m_renderWidth, m_renderHeight));
+
+ m_renderPlane.draw(m_2DLightingShader);
+ }
+
+ // 2D Lighting
+ {
+ // glViewport(0, 0, m_windowWidth, m_windowHeight);
+
+ m_2DPostProcessRender.bind();
+
+ m_2DLightingShader.use();
+ m_2DLightingShader.setUniform("u_camMatrix", sceneCamera.view);
+ m_2DLightingShader.setUniform("u_time", scene.getTime());
+ m_2DLightingShader.setUniform("u_resolution", glm::vec2(m_renderWidth, m_renderHeight));
+
+ GLuint colorTextureLocation = glGetUniformLocation(m_2DLightingShader.ID, "t_colorTexture");
+ glUniform1i(colorTextureLocation, 0);
+
+ m_postProcessDoubleBuffer[!horizontal]->getColorAttachment()->bind(0);
+
+ GLuint distanceTextureLocation = glGetUniformLocation(m_2DLightingShader.ID, "t_distanceTexture");
+ glUniform1i(distanceTextureLocation, 1);
+ m_distanceTexture.bind(1);
+
+ GLuint backgroundTextureLocation = glGetUniformLocation(m_2DLightingShader.ID, "t_backgroundTexture");
+ glUniform1i(backgroundTextureLocation, 2);
+ m_2DBackgroundTexture.bind(2);
+
+ m_renderPlane.draw(m_2DLightingShader);
+ m_postProcessTextureFront.unbind();
}
}
@@ -370,7 +482,7 @@ namespace WeirdEngine
glUniform1i(u_colorTextureLocation3d, 1);
m_3DSceneTexture.bind(1);
- m_renderPlane.draw(m_postProcessShaderProgram);
+ m_renderPlane.draw(m_2DLightingShader);
m_lit2DSceneTexture.unbind();
m_3DSceneTexture.unbind();
@@ -378,19 +490,7 @@ namespace WeirdEngine
output(scene, m_combineResultTexture);
}
- void Renderer::renderFire(Scene& scene, Camera& camera, float time)
- {
- }
-
- void Renderer::renderGeometry(Scene& scene, Camera& camera)
- {
- }
-
- bool Renderer::checkWindowClosed() const
- {
- return false;
- }
void Renderer::setWindowTitle(const char* name)
{
diff --git a/src/weird-renderer/shaders/2DBackground.frag b/src/weird-renderer/shaders/2DBackground.frag
new file mode 100644
index 0000000..2238d10
--- /dev/null
+++ b/src/weird-renderer/shaders/2DBackground.frag
@@ -0,0 +1,37 @@
+#version 330 core
+
+// Constants
+
+// Outputs u_staticColors in RGBA
+layout(location = 0) out vec4 FragColor;
+
+// Inputs from vertex shader
+in vec3 v_worldPos;
+in vec3 v_normal;
+in vec3 v_color;
+in vec2 v_texCoord;
+
+uniform mat4 u_camMatrix;
+uniform vec2 u_resolution;
+uniform float u_time;
+
+void main()
+{
+ vec2 screenUV = gl_FragCoord.xy / u_resolution.xy;
+
+ vec2 uv = (2.0 * v_texCoord) - 1.0;
+ uv.x *= (u_resolution.x / u_resolution.y);
+
+ float zoom = -1.5 * u_camMatrix[3].z;
+ vec2 pos = (zoom * uv) - u_camMatrix[3].xy;
+ float aspectRatio = u_resolution.x / u_resolution.y;
+ vec2 zoomVec = vec2((zoom * aspectRatio) - 1.0, zoom);
+
+ vec2 pixel = 0.2 * zoom / u_resolution;
+ pixel.x *= aspectRatio;
+
+ vec3 background = mix(vec3(0.55), vec3(0.7),
+ (fract(0.1 * pos.x) > pixel.x && fract(0.1 * pos.y) > pixel.y) ? 1.0 : 0.0);
+
+ FragColor = vec4(background, 1.0);
+}
\ No newline at end of file
diff --git a/src/weird-renderer/shaders/2DLightingShader.frag b/src/weird-renderer/shaders/2DLightingShader.frag
new file mode 100644
index 0000000..f9a3dcb
--- /dev/null
+++ b/src/weird-renderer/shaders/2DLightingShader.frag
@@ -0,0 +1,216 @@
+#version 330 core
+
+#define SHADOWS_ENABLED
+// #define SOFT_SHADOWS
+// #define DITHERING
+
+// #define DEBUG_SHOW_DISTANCE
+// #define DEBUG_SHOW_COLORS
+
+// Constants
+const int MAX_STEPS = 1000;
+const float EPSILON = 0.0;
+const float NEAR = 0.1f;
+const float FAR = 1.2f;
+
+// Outputs u_staticColors in RGBA
+layout(location = 0) out vec4 FragColor;
+
+// Inputs from vertex shader
+in vec3 v_worldPos;
+in vec3 v_normal;
+in vec3 v_color;
+in vec2 v_texCoord;
+
+uniform mat4 u_camMatrix;
+uniform vec2 u_resolution;
+uniform float u_time;
+
+uniform sampler2D t_colorTexture;
+uniform sampler2D t_distanceTexture;
+uniform sampler2D t_backgroundTexture;
+
+uniform vec2 u_directionalLightDirection = vec2(0.7071f, 0.7071f);
+
+#ifdef DITHERING
+
+uniform float u_spread = .5;
+uniform int u_colorCount = 4;
+
+// Dithering and posterizing
+uniform int u_bayer2[2 * 2] = int[2 * 2](
+0, 2,
+3, 1);
+
+uniform int u_bayer4[4 * 4] = int[4 * 4](
+0, 8, 2, 10,
+12, 4, 14, 6,
+3, 11, 1, 9,
+15, 7, 13, 5);
+
+uniform int u_bayer8[8 * 8] = int[8 * 8](
+0, 32, 8, 40, 2, 34, 10, 42,
+48, 16, 56, 24, 50, 18, 58, 26,
+12, 44, 4, 36, 14, 46, 6, 38,
+60, 28, 52, 20, 62, 30, 54, 22,
+3, 35, 11, 43, 1, 33, 9, 41,
+51, 19, 59, 27, 49, 17, 57, 25,
+15, 47, 7, 39, 13, 45, 5, 37,
+63, 31, 55, 23, 61, 29, 53, 21);
+
+float Getu_bayer2(int x, int y)
+{
+ return float(u_bayer2[(x % 2) + (y % 2) * 2]) * (1.0f / 4.0f) - 0.5f;
+}
+
+float Getu_bayer4(int x, int y)
+{
+ return float(u_bayer4[(x % 4) + (y % 4) * 4]) * (1.0f / 16.0f) - 0.5f;
+}
+
+float Getu_bayer8(int x, int y)
+{
+ return float(u_bayer8[(x % 8) + (y % 8) * 8]) * (1.0f / 64.0f) - 0.5f;
+}
+
+#endif
+
+float map(vec2 p)
+{
+ return texture(t_distanceTexture, p).x;
+}
+
+float rayMarch(vec2 ro, vec2 rd, out float minDistance)
+{
+ float d;
+ minDistance = 10000.0;
+
+ float traveled = 0.0;
+
+ for (int i = 0; i < MAX_STEPS; i++)
+ {
+ vec2 p = ro + (traveled * rd);
+
+ d = map(p);
+
+ minDistance = min(d, minDistance);
+
+ if (d <= EPSILON)
+ break;
+
+ if (p.x <= 0.0 || p.x >= 1.0 || p.y <= 0.0 || p.y >= 1.0)
+ return FAR;
+
+ // traveled += 0.01;
+ traveled += d;
+ // traveled += min(d, 0.01);
+
+ if (traveled >= FAR)
+ {
+ return FAR;
+ }
+ }
+
+ return traveled;
+}
+
+float render(vec2 uv)
+{
+
+ #ifdef SHADOWS_ENABLED
+
+ // Point light
+ vec2 rd = normalize(vec2(1.0) - uv);
+
+ // Directional light
+ // vec2 rd = u_directionalLightDirection.xy;
+
+ float d = map(uv);
+ float minD;
+ vec2 offsetPosition = uv + (2.0 / u_resolution) * rd;// 2 pixels towards the light
+
+ if (d <= 0.0)
+ {
+
+ // float dd = -max(-0.05, d) - 0.01;
+ // dd = max(0.0, dd);
+ float distanceFallof = 1.25;
+ float maxDistance = 0.05;
+
+ float dd = mix(0.0, 1.0, -(distanceFallof * d));// - 0.005;
+ dd = min(maxDistance, dd);
+
+ // Get distance at offset position
+ d = rayMarch(offsetPosition, rd, minD);
+ return d < FAR ? 1.0 + (-1.5f * dd) : 2.0;// * dot(n, rd);
+ }
+
+ d = rayMarch(uv, rd, minD);
+
+ // return (10.0 * minD)+0.5;
+
+ #ifdef SOFT_SHADOWS
+ return mix(0.85, 1.0, d / FAR);
+ #else
+ return d < FAR ? 0.85 : 1.0;
+ #endif
+
+ #else// No shadows
+
+ return 1.0;
+
+ #endif
+}
+
+void main()
+{
+ vec2 screenUV = v_texCoord;
+ vec4 colorSample = texture(t_colorTexture, screenUV);
+ vec3 color = colorSample.rgb;// + (0.25 * floor(colorSample.a));
+ vec4 data = texture(t_distanceTexture, screenUV);
+ float distance = data.x;
+
+ vec3 backgroundColor = texture(t_backgroundTexture, screenUV).rgb;// vec3(0.35);
+
+ float aaWidth = 0.0;
+ float edge = smoothstep(0.0, aaWidth, distance);// aaWidth controls softness
+
+ #ifdef DEBUG_SHOW_COLORS
+ edge = 0.0;
+ #endif
+
+ color = mix(color, backgroundColor, edge);
+
+ #ifdef DEBUG_SHOW_DISTANCE
+
+
+ float value = 0.5 * (cos(500.0 * distance) + 1.0);
+ value = value * value * value;
+ vec3 debugColor = distance > 0 ? mix(vec3(1), vec3(0.2), value) :// outside
+ (distance + 1.0) * mix(vec3(1.0, 0.2, 0.2), vec3(0.1), value);// inside
+
+ FragColor = vec4(debugColor, 1.0);
+
+
+ return;
+ #endif
+
+
+ float light = render(screenUV);
+ vec3 col = light * color.xyz;
+
+ #ifdef DITHERING
+
+ int x = int(gl_FragCoord.x);
+ int y = int(gl_FragCoord.y);
+ col = col + u_spread * Getu_bayer4(x, y);
+
+ col.r = floor((u_colorCount - 1.0f) * col.r + 0.5) / (u_colorCount - 1.0f);
+ col.g = floor((u_colorCount - 1.0f) * col.g + 0.5) / (u_colorCount - 1.0f);
+ col.b = floor((u_colorCount - 1.0f) * col.b + 0.5) / (u_colorCount - 1.0f);
+
+ #endif
+
+
+ FragColor = vec4(col.xyz, 1.0);
+}
diff --git a/src/weird-renderer/shaders/2DMaterialBlendShader.frag b/src/weird-renderer/shaders/2DMaterialBlendShader.frag
new file mode 100644
index 0000000..44175a3
--- /dev/null
+++ b/src/weird-renderer/shaders/2DMaterialBlendShader.frag
@@ -0,0 +1,52 @@
+#version 330 core
+
+// Outputs colors in RGBA
+out vec4 FragColor;
+
+in vec2 v_texCoord;
+
+uniform sampler2D t_colorTexture;
+
+uniform bool u_horizontal;
+uniform float u_weight[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
+uniform float u_time;
+
+
+
+vec3 toLinear(vec3 srgb) {
+ return pow(srgb, vec3(2.2));// or use inverse gamma
+}
+vec3 toSRGB(vec3 linear) {
+ return pow(linear, vec3(1.0 / 2.2));
+}
+
+float hash(vec2 p) {
+ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
+}
+
+void main()
+{
+ vec2 tex_offset = 1.0 / textureSize(t_colorTexture, 0);
+ vec2 uv = tex_offset + vec2(hash(gl_FragCoord.xy + u_time));
+
+ vec4 data = texture(t_colorTexture, v_texCoord);
+ float mask = data.w;
+
+ vec3 originalColor = toLinear(data.rgb);
+ vec3 result = originalColor * u_weight[0];// TODO: precompute toLinear before this shader
+
+ for (int i = 1; i < 5; ++i)
+ {
+ vec2 offset = u_horizontal ? vec2((tex_offset.x * i), 0.0) : vec2(0.0, (tex_offset.y * i)); // (tex_offset.x * i) + hash(gl_FragCoord.xy + u_time)
+
+ vec4 colRight = texture(t_colorTexture, v_texCoord + offset);
+ result += mix(toLinear(colRight.rgb), originalColor, 1.0 - colRight.a) * u_weight[i];
+
+ vec4 colLeft = texture(t_colorTexture, v_texCoord - offset);
+ result += mix(toLinear(colLeft.rgb), originalColor, 1.0 - colLeft.a) * u_weight[i];
+ }
+
+ result = toSRGB(result);
+ FragColor = vec4(mix(data.xyz, result, mask), data.a);
+ // FragColor = vec4(vec3(mask), data.w);
+}
diff --git a/src/weird-renderer/shaders/2DMaterialColorShader.frag b/src/weird-renderer/shaders/2DMaterialColorShader.frag
new file mode 100644
index 0000000..d88895b
--- /dev/null
+++ b/src/weird-renderer/shaders/2DMaterialColorShader.frag
@@ -0,0 +1,52 @@
+#version 330 core
+
+#define DEBUG_SHOW_DISTANCE 0
+
+// Constants
+
+// Outputs u_staticColors in RGBA
+layout(location = 0) out vec4 FragColor;
+
+// Inputs from vertex shader
+in vec3 v_worldPos;
+in vec3 v_normal;
+in vec3 v_color;
+in vec2 v_texCoord;
+
+uniform mat4 u_camMatrix;
+uniform vec2 u_resolution;
+uniform float u_time;
+
+uniform sampler2D t_materialDataTexture;
+uniform sampler2D t_currentColorTexture;
+uniform vec3 u_staticColors[16];
+
+vec3 randomColor(int index) {
+ float seed = float(index) * 43758.5453;
+ float r = fract(sin(seed) * 43758.5453);
+ float g = fract(sin(seed + 1.0) * 43758.5453);
+ float b = fract(sin(seed + 2.0) * 43758.5453);
+ return vec3(r, g, b);
+}
+
+void main()
+{
+ vec2 screenUV = v_texCoord;
+ vec4 color = texture(t_materialDataTexture, screenUV);
+ float distance = color.x;
+ int materialId = int(color.y);
+ float mask = color.z;
+ vec3 c = u_staticColors[materialId];
+
+ float zoom = -u_camMatrix[3].z;
+
+ vec3 currentColor = texture(t_currentColorTexture, screenUV).xyz;
+
+ // TODO: uniform?
+ float zoomFactor = (zoom - 10.0) * 0.02;
+ zoomFactor = smoothstep(0.0, 1.0, zoomFactor);
+ c = mix(c, currentColor, 0.9 * (1.0 - zoomFactor) * mask);
+
+ FragColor = vec4(c, mask);
+}
+
diff --git a/src/weird-renderer/shaders/2DSDFDistanceShader.frag b/src/weird-renderer/shaders/2DSDFDistanceShader.frag
new file mode 100644
index 0000000..e9df460
--- /dev/null
+++ b/src/weird-renderer/shaders/2DSDFDistanceShader.frag
@@ -0,0 +1,246 @@
+#version 330 core
+
+#define BLEND_SHAPES 1
+#define MOTION_BLUR 1
+
+out vec4 FragColor;
+
+// Inputs from vertex shader
+in vec3 v_worldPos;
+in vec3 v_normal;
+in vec3 v_color;
+in vec2 v_texCoord;
+
+// Uniforms
+uniform sampler2D u_diffuse;
+uniform sampler2D u_specular;
+
+uniform vec4 u_lightColor;
+uniform vec3 u_lightPos;
+uniform vec3 u_camPos;
+
+uniform float u_time;
+uniform float u_k = 0.5;
+uniform sampler2D t_colorTexture;
+
+uniform int u_loadedObjects;
+uniform samplerBuffer t_shapeBuffer;
+
+uniform vec2 u_resolution;
+
+uniform mat4 u_camMatrix;
+uniform vec3 u_staticColors[16];
+uniform vec3 u_directionalLightDirection;
+
+uniform int u_blendIterations;
+
+uniform int u_customShapeCount;
+
+uniform float u_uiScale = 50.0f;
+
+// Constants
+const int MAX_STEPS = 100;
+const float EPSILON = 0.01;
+const float NEAR = 0.1f;
+const float FAR = 100.0f;
+
+// Custom shape variables
+#define var8 u_time
+#define var9 p.x
+#define var10 p.y
+#define var11 u_uiScale * uv.x
+#define var12 u_uiScale * uv.y
+
+#define var0 parameters0.x
+#define var1 parameters0.y
+#define var2 parameters0.z
+#define var3 parameters0.w
+#define var4 parameters1.x
+#define var5 parameters1.y
+#define var6 parameters1.z
+#define var7 parameters1.w
+
+// Operations
+float fOpUnionSoft(float a, float b, float r)
+{
+ float e = max(r - abs(a - b), 0);
+ return min(a, b) - e * e * 0.25 / r;
+}
+
+float fOpUnionSoft(float a, float b, float r, float invR)
+{
+ float e = max(r - abs(a - b), 0);
+ return min(a, b) - e * e * 0.25 * invR;
+}
+
+float smin(float a, float b, float u_k)
+{
+ float h = clamp(0.5 + 0.5 * (b - a) / u_k, 0.0, 1.0);
+ return mix(b, a, h) - u_k * h * (1.0 - h);
+}
+
+float shape_circle(vec2 p)
+{
+ return length(p) - 0.5;
+}
+
+// y = sin(5x + t) / 5
+// 0 = sin(5x + t) / 5 - y
+float shape_sine(vec2 p)
+{
+ return p.y - sin(p.x * 5.0 + u_time) * 0.2;
+}
+
+float shape_box2d(vec2 p, vec2 b)
+{
+ vec2 d = abs(p) - b;
+ return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
+}
+
+float shape_line(vec2 p, vec2 a, vec2 b)
+{
+ vec2 dir = b - a;
+ return abs(dot(normalize(vec2(dir.y, -dir.x)), a - p));
+}
+
+float shape_segment(vec2 p, vec2 a, vec2 b)
+{
+ float d = shape_line(p, a, b);
+ float d0 = dot(p - b, b - a);
+ float d1 = dot(p - a, b - a);
+ return d1 < 0.0 ? length(a - p) : d0 > 0.0 ? length(b - p)
+ : d;
+}
+
+float shape_circles_smin(vec2 p, float t)
+{
+ return smin(shape_circle(p - vec2(cos(t))), shape_circle(p + vec2(sin(t), 0)), 0.8);
+}
+
+vec3 draw_line(float d, float thicu_kness)
+{
+ const float aa = 3.0;
+ return vec3(smoothstep(0.0, aa / u_resolution.y, max(0.0, abs(d) - thicu_kness)));
+}
+
+vec3 draw_line(float d)
+{
+ return draw_line(d, 0.0025);
+}
+
+vec3 getMaterial(vec2 p, int materialId)
+{
+ return u_staticColors[materialId];
+}
+
+vec3 getColor(vec2 p, vec2 uv)
+{
+ float minDist = 100000.0;
+ float minColorDist = minDist;
+
+ int finalMaterialId = 0;
+ float mask = 1.0;
+
+ /*ADD_SHAPES_HERE*/
+
+ if (minDist <= 0.0)
+ {
+ return vec3(minDist, finalMaterialId, 0.0);
+ }
+
+ float shapeDist = minDist;
+ minDist = 1.0; // Disable blending between balls and shapes
+
+ float inv_k = 1.0 / u_k;
+
+ for (int i = 0; i < u_loadedObjects - (2 * u_customShapeCount); i++)
+ {
+ vec4 positionSizeMaterial = texelFetch(t_shapeBuffer, i);
+ int materialId = int(positionSizeMaterial.w);
+
+ float objectDist = shape_circle(p - positionSizeMaterial.xy);
+
+ // Inside ball mask is set to 0
+ mask = objectDist <= 0 ? 0.95 : mask;
+
+ #if BLEND_SHAPES
+
+ finalMaterialId = objectDist <= minColorDist ? materialId : finalMaterialId;
+
+ #else
+
+ finalMaterialId = objectDist <= minDist ? materialId : finalMaterialId;
+
+ #endif
+
+
+ #if BLEND_SHAPES
+
+ minDist = fOpUnionSoft(objectDist, minDist, u_k, inv_k);
+ minColorDist = min(minColorDist, objectDist);
+
+ #else
+
+ minDist = min(minDist, objectDist);
+
+
+
+ #endif
+
+ }
+
+ minDist = min(minDist, shapeDist);
+
+ return vec3(minDist, finalMaterialId, mask);
+}
+
+void main()
+{
+ // FragColor = vec4(u_customShapeCount);
+ // return;
+
+ vec2 uv = (2.0f * v_texCoord) - 1.0f;
+ float aspectRatio = u_resolution.x / u_resolution.y;// TODO: uniform
+ uv.x *= aspectRatio;
+
+ float zoom = -u_camMatrix[3].z;
+ vec2 pos = (zoom * uv) - u_camMatrix[3].xy;
+
+
+ vec3 result = getColor(pos, v_texCoord);// Same as uv but (0, 0) is bottom left corner
+ float distance = result.x;
+
+ float finalDistance = 0.5 * distance / zoom;
+ finalDistance *= 0.5 / aspectRatio;
+
+
+
+ #if MOTION_BLUR
+
+ vec2 screenUV = v_texCoord;
+ vec4 previousColor = texture(t_colorTexture, screenUV.xy);
+
+ float previousDistance = previousColor.x;
+ int previousMaterial = int(previousColor.y);
+ result.y = finalDistance > 0.0 && previousDistance < 0.0 ? previousColor.y : result.y;
+
+ previousDistance += u_blendIterations * 0.00035;
+ previousDistance = mix(finalDistance, previousDistance, 0.95);
+ // previousDistance = min(previousDistance + (u_blendIterations * 0.00035), mix(finalDistance, previousDistance, 0.9));
+
+ finalDistance = min(previousDistance, finalDistance);
+
+
+ // FragColor = previousColor;
+
+ // FragColor = mix(vec4(color.xyz, finalDistance), previousColor, 0.9);
+
+ #else
+
+
+
+ #endif
+
+ FragColor = vec4(finalDistance, result.y, result.z, 0);
+
+}
diff --git a/src/weird-renderer/shaders/postProcess2d.frag b/src/weird-renderer/shaders/PostProcessShader.frag
similarity index 96%
rename from src/weird-renderer/shaders/postProcess2d.frag
rename to src/weird-renderer/shaders/PostProcessShader.frag
index 0879171..d65948f 100644
--- a/src/weird-renderer/shaders/postProcess2d.frag
+++ b/src/weird-renderer/shaders/PostProcessShader.frag
@@ -15,6 +15,13 @@ const float FAR = 1.2f;
// Outputs u_staticColors in RGBA
layout(location = 0) out vec4 FragColor;
+// Inputs from vertex shader
+in vec3 v_worldPos;
+in vec3 v_normal;
+in vec3 v_color;
+in vec2 v_texCoord;
+
+uniform mat4 u_camMatrix;
uniform vec2 u_resolution;
uniform float u_time;
diff --git a/src/weird-renderer/shaders/backgroundGrid.frag b/src/weird-renderer/shaders/backgroundGrid.frag
index b329821..e5809d3 100644
--- a/src/weird-renderer/shaders/backgroundGrid.frag
+++ b/src/weird-renderer/shaders/backgroundGrid.frag
@@ -7,6 +7,7 @@ in vec2 v_texCoord;
uniform mat4 u_camMatrix;
uniform float u_fov;
+uniform vec2 u_resolution;
uniform float gridScale = 1.0; // Size of each grid cell in world units
uniform vec3 gridColor = vec3(1); // Color of the grid lines
@@ -41,6 +42,9 @@ void main()
{
// Bring 0,0 to the center of the screen
vec2 uv = (2.0 * v_texCoord) - 1.0;
+ float aspectRatio = u_resolution.x / u_resolution.y;
+ uv.x *= 2.0 * aspectRatio;
+
// Calculate the direction of a ray that goes from origin towards the frag coord
// This formula is often used in ray marching, I don't know where I got it for the first
// time at this point
diff --git a/src/weird-renderer/shaders/raymarching.frag b/src/weird-renderer/shaders/raymarching.frag
index 7761112..215c3f5 100644
--- a/src/weird-renderer/shaders/raymarching.frag
+++ b/src/weird-renderer/shaders/raymarching.frag
@@ -397,13 +397,11 @@ float rand(vec2 co){
void main()
{
-
- float aspectRatio = u_resolution.x / u_resolution.y;
- vec2 pixelScale = vec2(aspectRatio * 0.2, 0.2);
-
vec2 screenUV = v_texCoord;
vec2 uv = (2.0f * v_texCoord) - 1.0f;
+ float aspectRatio = u_resolution.x / u_resolution.y; // TODO: uniform
+ uv.x *= aspectRatio;
// Calculate true z value from the depth buffer: https://stackoverflow.com/questions/6652253/getting-the-true-z-value-from-the-depth-buffer
float depth = texture(t_depthTexture, screenUV).r;
diff --git a/src/weird-renderer/shaders/raymarching2d.frag b/src/weird-renderer/shaders/raymarching2d.frag
deleted file mode 100644
index 9a4eb52..0000000
--- a/src/weird-renderer/shaders/raymarching2d.frag
+++ /dev/null
@@ -1,244 +0,0 @@
-#version 330 core
-
-
-out vec4 FragColor;
-
-// Inputs from vertex shader
-in vec3 v_worldPos;
-in vec3 v_normal;
-in vec3 v_color;
-in vec2 v_texCoord;
-
-// Uniforms
-uniform sampler2D u_diffuse;
-uniform sampler2D u_specular;
-
-uniform vec4 u_lightColor;
-uniform vec3 u_lightPos;
-uniform vec3 u_camPos;
-
-uniform float u_time;
-
-// Custom
-
-#define BLEND_SHAPES 0
-#define MOTION_BLUR 1
-
-uniform float u_k = 0.25;
-// Uniforms
-uniform sampler2D t_colorTexture;
-
-uniform int u_loadedObjects;
-uniform samplerBuffer t_shapeBuffer;
-
-uniform vec2 u_resolution;
-
-uniform mat4 u_camMatrix;
-uniform vec3 u_staticColors[16];
-uniform vec3 u_directionalLightDirection;
-
-uniform int u_blendIterations;
-
-uniform int u_customShapeCount;
-
-uniform float u_uiScale = 50.0f;
-
-// Constants
-const int MAX_STEPS = 100;
-const float EPSILON = 0.01;
-const float NEAR = 0.1f;
-const float FAR = 100.0f;
-
-// Custom shape variables
-#define var8 u_time
-#define var9 p.x
-#define var10 p.y
-#define var11 u_uiScale * uv.x
-#define var12 u_uiScale * uv.y
-
-#define var0 parameters0.x
-#define var1 parameters0.y
-#define var2 parameters0.z
-#define var3 parameters0.w
-#define var4 parameters1.x
-#define var5 parameters1.y
-#define var6 parameters1.z
-#define var7 parameters1.w
-
-// Operations
-float fOpUnionSoft(float a, float b, float r)
-{
- float e = max(r - abs(a - b), 0);
- return min(a, b) - e * e * 0.25 / r;
-}
-
-float fOpUnionSoft(float a, float b, float r, float invR)
-{
- float e = max(r - abs(a - b), 0);
- return min(a, b) - e * e * 0.25 * invR;
-}
-
-float smin(float a, float b, float u_k)
-{
- float h = clamp(0.5 + 0.5 * (b - a) / u_k, 0.0, 1.0);
- return mix(b, a, h) - u_k * h * (1.0 - h);
-}
-
-float shape_circle(vec2 p)
-{
- return length(p) - 0.5;
-}
-
-// y = sin(5x + t) / 5
-// 0 = sin(5x + t) / 5 - y
-float shape_sine(vec2 p)
-{
- return p.y - sin(p.x * 5.0 + u_time) * 0.2;
-}
-
-float shape_box2d(vec2 p, vec2 b)
-{
- vec2 d = abs(p) - b;
- return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
-}
-
-float shape_line(vec2 p, vec2 a, vec2 b)
-{
- vec2 dir = b - a;
- return abs(dot(normalize(vec2(dir.y, -dir.x)), a - p));
-}
-
-float shape_segment(vec2 p, vec2 a, vec2 b)
-{
- float d = shape_line(p, a, b);
- float d0 = dot(p - b, b - a);
- float d1 = dot(p - a, b - a);
- return d1 < 0.0 ? length(a - p) : d0 > 0.0 ? length(b - p)
- : d;
-}
-
-float shape_circles_smin(vec2 p, float t)
-{
- return smin(shape_circle(p - vec2(cos(t))), shape_circle(p + vec2(sin(t), 0)), 0.8);
-}
-
-vec3 draw_line(float d, float thicu_kness)
-{
- const float aa = 3.0;
- return vec3(smoothstep(0.0, aa / u_resolution.y, max(0.0, abs(d) - thicu_kness)));
-}
-
-vec3 draw_line(float d)
-{
- return draw_line(d, 0.0025);
-}
-
-vec3 getMaterial(vec2 p, int materialId)
-{
- return u_staticColors[materialId];
-}
-
-vec4 getColor(vec2 p, vec2 uv)
-{
- float minDist = 100000.0;
-
- vec3 col = vec3(0.0);
- float minZ = 1000.0f;
-
- float zoom = -u_camMatrix[3].z;
-
- float aspectRatio = u_resolution.x / u_resolution.y;
- vec2 zoomVec = vec2((zoom * aspectRatio) - 1.0, zoom);
-
- bool bestIsScreenSpace = false;
-
- /*ADD_SHAPES_HERE*/
-
- if(minDist < EPSILON)
- {
- return vec4(col, minDist);
- }
-
- for (int i = 0; i < u_loadedObjects - (2 * u_customShapeCount); i++)
- {
- vec4 positionSizeMaterial = texelFetch(t_shapeBuffer, i);
- int materialId = int(positionSizeMaterial.w);
- // vec4 extraParameters = texelFetch(t_shapeBuffer, (2 * i) + 1);
-
- float z = positionSizeMaterial.z;
-
- float objectDist = shape_circle(p - positionSizeMaterial.xy);
-
- #if BLEND_SHAPES
-
- minDist = fOpUnionSoft(objectDist, minDist, u_k);
- float delta = 1 - (max(u_k - abs(objectDist - minDist), 0.0) / u_k); // After new d is calculated
- col = mix(getMaterial(p, materialId), col, delta);
-
- #else
-
- if(objectDist < minDist)
- {
- minDist = objectDist;
- col = getMaterial(positionSizeMaterial.xy, materialId);
- minZ = z;
-
- if(minDist < EPSILON)
- {
- break;
- }
- }
-
- #endif
-
- }
-
- // Set bacu_kground color
- // vec3 bacu_kground = mix(u_staticColors[2], u_staticColors[3], mod(floor(.1 * p.x) + floor(.1 * p.y), 2.0));
- float pixel = 0.2 / u_resolution.y;
- vec3 background = mix(u_staticColors[3], u_staticColors[2], min(fract(0.1 * p.x), fract(0.1 * p.y)) > pixel * zoom ? 1.0 : 0.0);
- col = minDist > 0.0 ? background : col;
-
- return vec4(col, minDist);
-}
-
-void main()
-{
- // FragColor = vec4(u_customShapeCount);
- // return;
-
- vec2 uv = (2.0f * v_texCoord) - 1.0f;
-
- float zoom = -u_camMatrix[3].z;
- vec2 pos = (zoom * uv) - u_camMatrix[3].xy;
-
- vec4 color = getColor(pos, v_texCoord); // Same as uv but (0, 0) is bottom left corner
- float distance = color.w;
-
- float finalDistance = 0.6667 * 0.5 * distance / zoom;
-
-#if MOTION_BLUR
-
- vec2 screenUV = v_texCoord;
- vec4 previousColor = texture(t_colorTexture, screenUV.xy);
- float previousDistance = previousColor.w;
-
- previousDistance += u_blendIterations * 0.00035;
- previousDistance = mix(finalDistance, previousDistance, 0.95);
- // previousDistance = min(previousDistance + (u_blendIterations * 0.00035), mix(finalDistance, previousDistance, 0.9));
-
- FragColor = previousDistance < finalDistance ? vec4(previousColor.xyz, previousDistance) : vec4(color.xyz, finalDistance);
- if (FragColor.w > 0.0)
- FragColor = vec4(color.xyz, FragColor.w);
-
- // FragColor = previousColor;
-
- // FragColor = mix(vec4(color.xyz, finalDistance), previousColor, 0.9);
-
-#else
-
- FragColor = vec4(color.xyz, finalDistance);
-
-#endif
-
-}