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 - -}