├── bin ├── clear_cmake.bat ├── apitrace.bat ├── build_and_run.bat ├── generate_makefile.clang.bat └── build_glsl.py ├── assets ├── Ratboy │ ├── Ratboy_mohawk.tfx │ └── LICENSE.txt └── sintel_lite_v2_1 │ └── GEO-sintel_hair_emit.001-sintel_hair.tfx ├── libs ├── tiny_obj_loader │ └── tiny_obj_loader.cpp ├── amd_tressfx │ ├── src │ │ ├── Readme.md │ │ ├── TressFXEngineInterface.h │ │ ├── Math │ │ │ └── Transform.cpp │ │ ├── TressFXFileFormat.h │ │ └── TressFXSimulation.cpp │ └── include │ │ ├── TressFXBoneSkeletonInterface.h │ │ ├── TressFXSimulation.h │ │ ├── TressFXSDFInputMeshInterface.h │ │ ├── Math │ │ ├── Transform.h │ │ ├── Matrix44.h │ │ ├── Quaternion.h │ │ ├── Matrix33.h │ │ └── Vector3D.h │ │ ├── TressFXCommon.h │ │ ├── TressFXSettings.h │ │ ├── TressFXPPLL.h │ │ └── TressFXShortCut.h └── imgui │ ├── imgui_impl_opengl3.h │ └── imgui_impl_sdl.h ├── src ├── shaders │ ├── wind.frag.glsl │ ├── capsule_debug.frag.glsl │ ├── gl-tfx │ │ ├── ppll_resolve.vert.glsl │ │ ├── lib │ │ │ ├── TressFXPPLL.glsl │ │ │ ├── TressFXRendering.coverage.glsl │ │ │ └── TressFXPPLL.build.glsl │ │ ├── ppll_build.vert.glsl │ │ ├── _utils.glsl │ │ ├── sim │ │ │ ├── _SimCapsuleCollision.comp.glsl │ │ │ ├── _SimBuffers.comp.glsl │ │ │ ├── _SimCommon.comp.glsl │ │ │ ├── _SimQuat.comp.glsl │ │ │ └── _SimParams.comp.glsl │ │ ├── ppll_resolve.frag.glsl │ │ ├── sim4_UpdateFollowHairVertices.comp.glsl │ │ ├── ppll_build.frag.glsl │ │ └── sim1_VelocityShockPropagation.comp.glsl │ ├── simple_obj.vert.glsl │ ├── bg.frag.glsl │ ├── capsule_debug.vert.glsl │ ├── bg.vert.glsl │ ├── _fullscreen_pass.glsl │ ├── wind.vert.glsl │ └── simple_obj.frag.glsl ├── gl-tfx │ ├── include_TFx_pls_no_warnings.hpp │ ├── GpuInterface │ │ ├── fileIO.impl.hpp │ │ ├── buffer.impl.hpp │ │ ├── barriers.impl.hpp │ │ └── TFxGpuInterface.hpp │ ├── print_me.hpp │ ├── TFxPPLL.hpp │ ├── TFxHairStrands.hpp │ ├── TFxSimulation.hpp │ ├── TFxSettings.hpp │ ├── TFxSample.hpp │ ├── TFxSimulation.cpp │ └── TFxHairStrands.cpp ├── gl-utils │ ├── main.cpp │ ├── buffer │ │ ├── buffer.impl.hpp │ │ ├── read.impl.hpp │ │ ├── copy_to.impl.hpp │ │ ├── write.impl.hpp │ │ └── malloc.impl.hpp │ ├── texture │ │ ├── apply_texture_options.impl.hpp │ │ └── allocate_texture.impl.hpp │ ├── vao.impl.hpp │ ├── uniforms.impl.hpp │ ├── shader │ │ └── shader.impl.hpp │ └── debug_callback.impl.hpp ├── utils.impl.hpp ├── State.hpp ├── camera_ortho.impl.hpp ├── logging │ ├── Logging.cpp │ └── formatter.impl.hpp └── scene.impl.hpp ├── cmake ├── Utils.cmake ├── Modules │ ├── FindGLAD.cmake │ ├── FindGLM.cmake │ └── FindSDL2.cmake └── Config.cmake ├── .gitignore ├── include ├── gl-utils │ ├── window.hpp │ ├── draw │ │ ├── depth.hpp │ │ ├── parameters.hpp │ │ ├── blend.hpp │ │ └── stencil.hpp │ ├── pch.hpp │ ├── uniform.types.hpp │ ├── VAO.hpp │ ├── texture │ │ ├── texture.hpp │ │ └── TextureOpts.hpp │ ├── shader │ │ └── introspect.hpp │ └── sync.hpp ├── logging │ └── Logger.hpp └── pch.hpp ├── LICENSE └── CMakeLists.txt /bin/clear_cmake.bat: -------------------------------------------------------------------------------- 1 | @rm CMakeCache.txt 2 | @rm cmake_install.cmake 3 | @rm -r CMakeFiles -------------------------------------------------------------------------------- /assets/Ratboy/Ratboy_mohawk.tfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Scthe/TressFX-OpenGL/HEAD/assets/Ratboy/Ratboy_mohawk.tfx -------------------------------------------------------------------------------- /libs/tiny_obj_loader/tiny_obj_loader.cpp: -------------------------------------------------------------------------------- 1 | #define TINYOBJLOADER_IMPLEMENTATION 2 | #include "tiny_obj_loader.h" 3 | -------------------------------------------------------------------------------- /src/shaders/wind.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | out vec4 out_color; 4 | 5 | void main() { 6 | out_color = vec4(1,0,1,1); 7 | } 8 | -------------------------------------------------------------------------------- /assets/sintel_lite_v2_1/GEO-sintel_hair_emit.001-sintel_hair.tfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Scthe/TressFX-OpenGL/HEAD/assets/sintel_lite_v2_1/GEO-sintel_hair_emit.001-sintel_hair.tfx -------------------------------------------------------------------------------- /src/shaders/capsule_debug.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | precision highp float; 3 | 4 | out vec4 gl_FragColor; 5 | 6 | void main(void) { 7 | gl_FragColor = vec4(0.56, 0.0, 1.0, 1.0); 8 | } 9 | -------------------------------------------------------------------------------- /src/gl-tfx/include_TFx_pls_no_warnings.hpp: -------------------------------------------------------------------------------- 1 | #pragma GCC diagnostic ignored "-Wgnu-anonymous-struct" 2 | #pragma GCC diagnostic ignored "-Wnested-anon-types" 3 | #pragma GCC diagnostic ignored "-Wunknown-pragmas" 4 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/ppll_resolve.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | #pragma include "../_fullscreen_pass.glsl" 4 | 5 | void main() { 6 | vec2 xy = get_fullscreen_pos(); 7 | gl_Position = vec4(xy, 1.0, 1.0); 8 | } 9 | -------------------------------------------------------------------------------- /src/shaders/simple_obj.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | in layout(location=0) vec3 in_Position; 3 | in layout(location=1) vec3 in_Normal; 4 | out vec3 v_Normal; 5 | uniform mat4 g_MVP; 6 | 7 | void main(void) { 8 | gl_Position = g_MVP * vec4(in_Position, 1.0f); 9 | v_Normal = in_Normal; 10 | } 11 | -------------------------------------------------------------------------------- /src/shaders/bg.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | uniform vec4 g_color_top; 4 | uniform vec4 g_color_bottom; 5 | uniform float g_screenHeight; 6 | 7 | out vec4 out_color; 8 | 9 | void main() { 10 | float fac = gl_FragCoord.y / g_screenHeight; 11 | out_color = mix(g_color_bottom, g_color_top, fac); 12 | } 13 | -------------------------------------------------------------------------------- /bin/apitrace.bat: -------------------------------------------------------------------------------- 1 | @rm *.trace 2 | @mv bin\opengl32.apitrace.dll bin\opengl32.dll 3 | 4 | @bin\TressFx.exe 5 | C:\programs\portable\apitrace\bin\qapitrace.exe TressFx.trace 6 | 7 | @REM @bin\tests.exe 8 | @REM C:\programs\portable\apitrace\bin\qapitrace.exe tests.trace 9 | 10 | @mv bin\opengl32.dll bin\opengl32.apitrace.dll 11 | -------------------------------------------------------------------------------- /src/gl-tfx/GpuInterface/fileIO.impl.hpp: -------------------------------------------------------------------------------- 1 | void TressFX_DefaultRead(void* ptr, AMD::uint size, EI_Stream* pFile) { 2 | FILE* fp = reinterpret_cast(pFile); 3 | fread(ptr, size, 1, fp); 4 | } 5 | 6 | void TressFX_DefaultSeek(EI_Stream* pFile, AMD::uint offset) { 7 | FILE* fp = reinterpret_cast(pFile); 8 | fseek(fp, offset, SEEK_SET); 9 | } 10 | -------------------------------------------------------------------------------- /src/shaders/capsule_debug.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | in layout(location=0) vec3 in_Position; 3 | uniform mat4 g_MVP; 4 | uniform vec4 g_Capsules[4]; 5 | 6 | void main(void) { 7 | vec4 capsule = g_Capsules[gl_InstanceID]; 8 | vec4 position = vec4(in_Position * capsule.w, 1.0f); 9 | position.xyz += capsule.xyz; 10 | gl_Position = g_MVP * position; 11 | } 12 | -------------------------------------------------------------------------------- /bin/build_and_run.bat: -------------------------------------------------------------------------------- 1 | @cls 2 | 3 | @python bin/build_glsl.py 4 | @if %errorlevel% neq 0 goto glsl_include_fail 5 | 6 | @make 7 | @if "%errorlevel%"=="0" goto success 8 | 9 | :failure 10 | @echo "--- compile/linking failed ---" 11 | @goto end 12 | 13 | :glsl_include_fail 14 | @echo "--- shader include resolve failed ---" 15 | @goto end 16 | 17 | :success 18 | @echo "--- compile/linking success ---" 19 | @bin\TressFx.exe 20 | 21 | :end 22 | -------------------------------------------------------------------------------- /src/shaders/bg.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | in vec3 position; 4 | 5 | 6 | const vec2 TOP_LEFT = vec2(-1.0, 1.0); 7 | const vec2 TOP_RIGHT = vec2( 1.0, 1.0); 8 | const vec2 BOT_LEFT = vec2(-1.0, -1.0); 9 | const vec2 BOT_RIGHT = vec2( 1.0, -1.0); 10 | 11 | const vec2 array[6] = vec2[6]( 12 | TOP_LEFT, BOT_LEFT, TOP_RIGHT, 13 | TOP_RIGHT, BOT_LEFT, BOT_RIGHT 14 | ); 15 | 16 | void main() { 17 | vec2 xy = array[gl_VertexID]; 18 | gl_Position = vec4(xy, 1.0, 1.0); 19 | } 20 | -------------------------------------------------------------------------------- /src/shaders/_fullscreen_pass.glsl: -------------------------------------------------------------------------------- 1 | // START _fullscreen_pass 2 | 3 | const vec2 TOP_LEFT = vec2(-1.0, 1.0); 4 | const vec2 TOP_RIGHT = vec2( 1.0, 1.0); 5 | const vec2 BOT_LEFT = vec2(-1.0, -1.0); 6 | const vec2 BOT_RIGHT = vec2( 1.0, -1.0); 7 | 8 | const vec2 FULLSCREEN_PASS_POSITIONS[6] = vec2[6]( 9 | TOP_LEFT, BOT_LEFT, TOP_RIGHT, 10 | TOP_RIGHT, BOT_LEFT, BOT_RIGHT 11 | ); 12 | 13 | vec2 get_fullscreen_pos () { 14 | return FULLSCREEN_PASS_POSITIONS[gl_VertexID]; 15 | } 16 | 17 | // END _fullscreen_pass 18 | -------------------------------------------------------------------------------- /cmake/Utils.cmake: -------------------------------------------------------------------------------- 1 | macro(set_with_default var default type docstring) 2 | if(NOT DEFINED ${var}) 3 | set(${var} ${default}) 4 | endif() 5 | set(${var} ${${var}} CACHE ${type} ${docstring} FORCE) 6 | endmacro() 7 | 8 | macro(assert_one_of var) 9 | if(NOT DEFINED ${var}) 10 | message(FATAL_ERROR "Variable for assert_one_of macro should be set") 11 | return() 12 | else() 13 | string(FIND ";${ARGN};" ";${var};" IDX2) 14 | if (IDX EQUAL -1) 15 | message(FATAL_ERROR "'${${var}}' should be one of ${ARGN}") 16 | return() 17 | endif() 18 | endif() 19 | endmacro() -------------------------------------------------------------------------------- /src/shaders/gl-tfx/lib/TressFXPPLL.glsl: -------------------------------------------------------------------------------- 1 | // START TressFXPPLL.glsl 2 | 3 | struct PPLL_STRUCT { 4 | uint depth; 5 | uint data; 6 | uint color; 7 | uint uNext; 8 | }; 9 | 10 | #define FRAGMENT_LIST_NULL 0xffffffff 11 | // #define HAS_COLOR 1 12 | 13 | uint PackFloat4IntoUint(vec4 vValue) { 14 | return ((uint(vValue.x * 255)) << 24) | 15 | ((uint(vValue.y * 255)) << 16) | 16 | ((uint(vValue.z * 255)) << 8) | 17 | uint(vValue.w * 255); 18 | } 19 | 20 | vec4 UnpackUintIntoFloat4(uint uValue) { 21 | uvec4 v = uvec4( 22 | (uValue & 0xFF000000) >> 24, 23 | (uValue & 0x00FF0000) >> 16, 24 | (uValue & 0x0000FF00) >> 8, 25 | (uValue & 0x000000FF) 26 | ); 27 | return vec4(v) / 255.0; 28 | } 29 | 30 | // END TressFXPPLL.glsl 31 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/ppll_build.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | #pragma include "_utils.glsl" 4 | #pragma include "lib/TressFXStrands.glsl" 5 | 6 | // START ppll_build.vert 7 | // (main) 8 | 9 | 10 | // model-view-projection matrix 11 | uniform mat4 g_mVP; 12 | // camera position 13 | uniform vec3 g_vEye; 14 | 15 | // in layout(location=0) vec3 in_Position; // unused 16 | out vec4 ps_Position; 17 | out vec4 ps_Tangent; 18 | out vec4 ps_p0p1; 19 | out vec4 ps_strandColor; 20 | 21 | void main(void) { 22 | TressFXVertex tressfxVert = GetExpandedTressFXVert(gl_VertexID, g_vEye, g_mVP); 23 | gl_Position = tressfxVert.Position; 24 | ps_Position = tressfxVert.Position; 25 | ps_Tangent = tressfxVert.Tangent; 26 | ps_p0p1 = tressfxVert.p0p1; 27 | ps_strandColor = tressfxVert.strandColor; 28 | } 29 | -------------------------------------------------------------------------------- /src/gl-utils/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../../include/gl-utils/main.hpp" 2 | 3 | #include "buffer/buffer.impl.hpp" 4 | #include "buffer/copy_to.impl.hpp" 5 | #include "buffer/malloc.impl.hpp" 6 | #include "buffer/read.impl.hpp" 7 | #include "buffer/write.impl.hpp" 8 | #include "draw/apply_parameters.impl.hpp" 9 | #include "texture/allocate_texture.impl.hpp" 10 | #include "texture/apply_texture_options.impl.hpp" 11 | #include "setShaderBuffer.impl.hpp" 12 | #include "shader/shader.impl.hpp" 13 | #include "uniforms.impl.hpp" 14 | #include "vao.impl.hpp" 15 | #include "window.impl.hpp" 16 | #include "debug_callback.impl.hpp" 17 | 18 | 19 | namespace glUtils { 20 | 21 | void async_write_barrier (AsyncWriteableResource_ resource_type) { 22 | GFX_GL_CALL(glMemoryBarrier, resource_type); 23 | } 24 | 25 | } // namespace glUtils 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/*exe 2 | bin/*dll 3 | bin/tmp 4 | 5 | CMakeCache.txt 6 | CMakeFiles 7 | cmake_install.cmake 8 | Makefile 9 | # cmake 10 | 11 | # bin 12 | bin/*.sh 13 | bin/generate_makefile.gcc.bat 14 | bin/glslcompiler 15 | 16 | # apitrace/renderdoc 17 | *.trace 18 | *.cap 19 | 20 | # assets - sintel 21 | assets/sintel_lite_v2_1/*.blend 22 | assets/sintel_lite_v2_1/textures/* 23 | assets/sintel_lite_v2_1/backup/* 24 | 25 | # assets - Ratboy 26 | assets/Ratboy/*.tfxbone 27 | assets/Ratboy/Ratboy_body.tfxmesh 28 | assets/Ratboy/Ratboy_left_hand.tfxmesh 29 | assets/Ratboy/Ratboy_right_hand.tfxmesh 30 | assets/Ratboy/Ratboy_short.tfx 31 | 32 | # PDFs / AMD repo etc. 33 | tressfx-reference 34 | libs/amd_tressfx/src/Shaders 35 | 36 | # misc 37 | src/shaders/generated 38 | imgui.ini 39 | gh-images 40 | 41 | # not used ATM 42 | libs/stb/ 43 | -------------------------------------------------------------------------------- /src/gl-utils/buffer/buffer.impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "./malloc.impl.hpp" 4 | #include "./read.impl.hpp" 5 | #include "./write.impl.hpp" 6 | #include "./copy_to.impl.hpp" 7 | 8 | namespace glUtils { 9 | 10 | void invalidate (const RawBuffer& buf, const BufferRange range_bytes) { 11 | auto is_whole_buffer = range_bytes.offset() == 0 && range_bytes.size() == buf.bytes; 12 | 13 | if (is_whole_buffer){ 14 | GFX_GL_CALL(glInvalidateBufferData, buf.gl_id); 15 | } else { 16 | GFX_GL_CALL(glInvalidateBufferSubData, buf.gl_id, range_bytes.offset(), range_bytes.size()); 17 | } 18 | } 19 | 20 | void destroy(RawBuffer& buf) { 21 | if (!buf.is_created()) { 22 | return; 23 | } 24 | 25 | invalidate(buf, {0, buf.bytes}); 26 | 27 | GFX_GL_CALL(glDeleteBuffers, 1, &buf.gl_id); 28 | 29 | buf.gl_id = GL_UTILS_NOT_CREATED_ID; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/shaders/wind.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | // in vec3 position; 4 | 5 | uniform vec4 g_WindDirection; 6 | uniform vec3 g_Eye; 7 | uniform mat4 g_VP; 8 | // uniform mat4 g_matProj; 9 | // uniform mat4 g_matView; 10 | 11 | const float TIP_DISTANCE = 0.3; 12 | const float END_DISTANCE = 0.5; 13 | const float END_SPREAD = 0.05; 14 | 15 | void main() { 16 | vec3 windDir = -g_WindDirection.xyz; 17 | 18 | vec3 tail = windDir * END_DISTANCE; 19 | vec3 towardsCamera = normalize(tail.xyz - g_Eye); 20 | vec3 up = cross(normalize(windDir), towardsCamera); 21 | up = normalize(up); 22 | 23 | vec3 vertices[3] = { 24 | windDir * TIP_DISTANCE, 25 | tail + END_SPREAD * up, 26 | tail - END_SPREAD * up 27 | }; 28 | gl_Position = g_VP * vec4(vertices[gl_VertexID], 1); 29 | // gl_Position = g_matProj * g_matView * vec4(vertices[gl_VertexID], 1); 30 | // gl_Position = p / p.w; 31 | } 32 | -------------------------------------------------------------------------------- /include/gl-utils/window.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace glUtils { 3 | 4 | struct WindowInitOpts { 5 | u32 x = 50, 6 | y = 50; 7 | u32 w = 640, 8 | h = 320; 9 | bool fullscreen = false; 10 | std::string title = "GlWindow"; 11 | 12 | bool vsync = false; 13 | i32 depth_buffer = 16; 14 | i32 stencil_buffer = 8; 15 | i32 msaa_samples = 1; 16 | bool use_srgb = false; 17 | u32 sdl_init_flags = 0; 18 | u32 sdl_window_flags = 0; 19 | // TODO double buffer using SDL_GL_DOUBLEBUFFER? 20 | 21 | struct { 22 | u8 major = 4; 23 | u8 minor = 5; // too lazy to update driver for 4.6 24 | } opengl_version; 25 | }; 26 | 27 | struct GlWindow { 28 | glm::uvec2 screen_size; 29 | SDL_Window* sdl_window = nullptr; 30 | SDL_Surface* sdl_surface = nullptr; 31 | void* gl_context; 32 | }; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/shaders/simple_obj.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | precision highp float; 3 | 4 | in vec3 v_Normal; 5 | out vec4 gl_FragColor; 6 | 7 | const vec3 LIGHT_POS = vec3(30.0, 30.0, 30.0); 8 | const float LIGHT_FALLOFF = 1.5; 9 | const vec3 AMBIENT = vec3(0.5); 10 | const float GAMMA = 2.2; 11 | 12 | vec3 tonemapReinhard (vec3 color) { 13 | return color / (color + vec3(1.0)); 14 | } 15 | 16 | vec3 gammaFix (vec3 color, float gamma) { 17 | return pow(color, vec3(1.0/gamma)); 18 | } 19 | 20 | void main(void) { 21 | // vec3 X = dFdx(v_Pos); 22 | // vec3 Y = dFdy(v_Pos); 23 | // vec3 v_Normal = normalize(cross(X,Y)); 24 | 25 | float dd = dot(normalize(v_Normal), normalize(LIGHT_POS)); 26 | float phong = max(0, dd); 27 | vec3 direct_light = vec3(phong) * LIGHT_FALLOFF; 28 | vec3 color = AMBIENT + direct_light; 29 | 30 | color = tonemapReinhard(color); 31 | gl_FragColor = vec4(gammaFix(color, GAMMA), 1.0); 32 | } 33 | -------------------------------------------------------------------------------- /include/gl-utils/draw/depth.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace glUtils { 4 | 5 | struct DepthTest { 6 | static const GLenum AlwaysFail = GL_NEVER; 7 | static const GLenum AlwaysPass = GL_ALWAYS; 8 | static const GLenum IfEqual = GL_EQUAL; 9 | static const GLenum IfNotEqual = GL_NOTEQUAL; 10 | static const GLenum IfMore = GL_GREATER; 11 | static const GLenum IfMoreOrEqual = GL_GEQUAL; 12 | static const GLenum IfLess = GL_LESS; 13 | static const GLenum IfLessOrEqual = GL_LEQUAL; 14 | }; 15 | typedef GLenum DepthTest_; 16 | 17 | struct Depth { 18 | DepthTest_ test = DepthTest::IfLess; 19 | bool write = true; 20 | // f32 range[2] = {0, 1}; 21 | // DepthClamp clamp = DepthClamp::NoClamp; 22 | }; 23 | 24 | inline bool operator==(const Depth& a, const Depth& b) { 25 | return (a.test == b.test) && (a.write == b.write); 26 | } 27 | 28 | inline bool operator!=(const Depth& a, const Depth& b) { 29 | return !(a == b); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/gl-tfx/print_me.hpp: -------------------------------------------------------------------------------- 1 | #include "GpuInterface/TFxGpuInterface.hpp" 2 | 3 | namespace AMD { class TressFXAsset; } 4 | 5 | namespace glTFx { 6 | struct TFxSettings; 7 | } 8 | 9 | namespace glTFx::debug { 10 | 11 | void debug_bindSet (const AMD::TressFXBindSet&); 12 | std::string debug_EI_Resource (const EI_Resource&); 13 | void debug_indexBuffer (AMD::uint32 indexCount, const EI_StringHash objectName); 14 | void debug_DrawParams (const AMD::EI_IndexedDrawParams&); 15 | void debug_layout (const AMD::TressFXLayoutDescription&); 16 | std::string debug_ShaderResource (const ShaderResource&); 17 | void debug_shader(const glUtils::Shader&); 18 | void debug_StructuredBuffer(const char* fnName, const EI_StringHash resourceName, 19 | const AMD::uint32 structSize, const AMD::uint32 structCount); 20 | void debug_asset(const char*const hairObjectName, const AMD::TressFXAsset& asset); 21 | void debug_shader_texts(const char* preamb, const glUtils::ShaderTexts&, int logLevel); 22 | void debug_settings(TFxSettings&); 23 | 24 | } // namespace glTFx::debug 25 | -------------------------------------------------------------------------------- /src/gl-tfx/TFxPPLL.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "include_TFx_pls_no_warnings.hpp" 4 | #include "../../libs/amd_tressfx/include/AMD_TressFX.h" 5 | 6 | #include 7 | #include "GpuInterface/TFxGpuInterface.hpp" 8 | 9 | // #include "SuTypes.h" 10 | // #include "SuArray.h" 11 | 12 | // lib forwards 13 | class TressFXPPLL; 14 | // class SuEffect; 15 | // class EI_PSO; 16 | 17 | 18 | namespace glTFx { 19 | 20 | class TFxHairStrands; 21 | 22 | class TFxPPLL { 23 | public: 24 | void initialize(int width, int height, 25 | int nNodes, int nodeSize, 26 | glUtils::Shader* pStrandEffect, glUtils::Shader* pQuadEffect); 27 | void shutdown(EI_Device* pDevice); 28 | 29 | void draw(std::vector& hairStrands, u32 nodePoolSize); 30 | 31 | private: 32 | TressFXPPLL* m_pPPLL = nullptr; // AMD lib 33 | 34 | /** shader + params used for building PPLL (pass 1)*/ 35 | EI_PSO m_pBuildPSO; 36 | /** shader + params for fullscreen pass (pass 2)*/ 37 | EI_PSO m_pReadPSO; 38 | }; 39 | 40 | } // namespace glTFx 41 | -------------------------------------------------------------------------------- /src/gl-tfx/TFxHairStrands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "include_TFx_pls_no_warnings.hpp" 4 | #include "../../libs/amd_tressfx/include/AMD_TressFX.h" 5 | 6 | // #include "SuString.h" 7 | // #include "SuTypes.h" 8 | // #include "SuObjectManager.h" 9 | 10 | class TressFXSimulation; 11 | 12 | namespace glTFx { 13 | 14 | class TFxHairStrands { 15 | public: 16 | 17 | void initialize( 18 | const char*const hairObjectName, 19 | const char*const tfxFilePath, 20 | // const char*const tfxboneFilePath, 21 | int numFollowHairsPerGuideHair, 22 | float tipSeparationFactor); 23 | void destroy(EI_Device* pDevice); 24 | 25 | void TransitionSimToRendering(EI_CommandContextRef); 26 | void TransitionRenderingToSim(EI_CommandContextRef); 27 | // void update_bones(EI_CommandContextRef); 28 | void simulate(EI_CommandContextRef, TressFXSimulation*); 29 | 30 | TressFXHairHandle get_AMDTressFXHandle() { return m_pStrands; } 31 | 32 | private: 33 | TressFXHairObject* m_pStrands = nullptr; 34 | }; 35 | 36 | } // namespace glTFx 37 | -------------------------------------------------------------------------------- /src/utils.impl.hpp: -------------------------------------------------------------------------------- 1 | static std::string get_file_contents(const char *filename) { 2 | std::ifstream in(filename, std::ios::in | std::ios::binary); 3 | if (in) { 4 | std::string contents; 5 | in.seekg(0, std::ios::end); 6 | contents.resize(in.tellg()); 7 | in.seekg(0, std::ios::beg); 8 | in.read(&contents[0], contents.size()); 9 | in.close(); 10 | return(contents); 11 | } else { 12 | LOGE << "Error reading file content: '" << filename << "'"; 13 | throw(errno); 14 | } 15 | } 16 | 17 | static void create_shader (Shader& shader, const std::string& p_vs, const std::string& f_vs) { 18 | ShaderTexts shader_texts; 19 | auto vs = get_file_contents(p_vs.c_str()); 20 | auto fs = get_file_contents(f_vs.c_str()); 21 | shader_texts.vertex = vs.c_str(); 22 | shader_texts.fragment = fs.c_str(); 23 | 24 | ShaderErrorsScratchpad es; 25 | shader = create_shader(shader_texts, es); 26 | if (!shader.is_created()) { 27 | LOGE << "Shader create error: " << es.msg; 28 | GFX_FAIL("Could not create scene shader [", 29 | p_vs.c_str(), ", ", f_vs.c_str(), 30 | "]"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Marcin Matuszczyk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /include/gl-utils/pch.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // No really pch, but.. 4 | 5 | #define GL_UTILS_NOT_CREATED_ID 0xffffffff 6 | 7 | // 8 | #pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" 9 | 10 | #define GFX_FAIL(...) \ 11 | { \ 12 | LOGE << "Assert failed (" << __FILE__ << ":" << __LINE__ << ") " APPLY(<<, __VA_ARGS__); \ 13 | /*DEBUG_BREAK();*/ \ 14 | assert(false); \ 15 | } 16 | 17 | #define GFX_FAIL_IF(condition, ...) \ 18 | if ((condition)) { \ 19 | GFX_FAIL("Failed condition '" , #condition , "' " , __VA_ARGS__) \ 20 | } 21 | 22 | #define GFX_FAIL_IF_NULL(PTR) \ 23 | if ((PTR) == nullptr) { \ 24 | GFX_FAIL("Expected pointer '" , #PTR , "' to not be null") \ 25 | } 26 | 27 | // 28 | 29 | // 30 | // @see https://github.com/JPGygax68/libGPCGLWrappers/blob/master/lib/include/gpc/gl/wrappers.hpp 31 | 32 | // #if defined (GFX_DEBUG) 33 | // # define GFX_GL_CALL(fn, ...) ::glUtils::utils::gl_call(#fn, __LINE__, __FILE__, fn, __VA_ARGS__) 34 | // #else 35 | # define GFX_GL_CALL(fn, ...) fn(__VA_ARGS__) 36 | // #endif 37 | 38 | // 39 | -------------------------------------------------------------------------------- /assets/Ratboy/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /libs/amd_tressfx/src/Readme.md: -------------------------------------------------------------------------------- 1 | TressFXAsset.cpp 2 | 1) instrumented with debug statements 3 | 2) add '#include ', otherwise memset is undefined 4 | 5 | 6 | TressFXSimulation.cpp 7 | 1) in TressFXSimulation::Simulate removed bindings. In OpenGL 8 | it is required to call glUseProgram before settings uniforms. 9 | This can only be done inside subsequent EI_Dispatch calls, 10 | so the binds were moved there. 11 | 12 | 13 | TressFXLayouts.cpp 14 | 1) in CreateSimLayout2() removed SRV: 15 | * g_HairStrandType (was unused?) 16 | * g_BoneSkinningData (no skinning support) 17 | NUM_SRVS was adjusted accordingly (7 to 5) 18 | 19 | 20 | TressFXHairObject.cpp 21 | 1) debug statements e.g. in InitialDataUpload when copying skipped data 22 | (skinning, simulation) 23 | 2) Removed references to unused SRVs(see TressFXLayouts.cpp): 24 | * mHairStrandTypeBuffer 25 | * mBoneSkinningDataBuffer 26 | EI_SRV SRVs[5]; // adjusted accordingly 27 | 3) Added: 28 | * `EI_BindSet& GetSimBindSet() { return *m_pSimBindSet; }` 29 | to TressFXHairObject class. Original code uses: 30 | `friend class TressFXSimulation;` 31 | -------------------------------------------------------------------------------- /src/gl-tfx/TFxSimulation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "include_TFx_pls_no_warnings.hpp" 5 | #include "../../libs/amd_tressfx/include/AMD_TressFX.h" // AMD forgot to import 6 | // #include "../../libs/amd_tressfx/include/TressFXSDFCollision.h" 7 | #include "../../libs/amd_tressfx/include/TressFXSimulation.h" 8 | 9 | // lib forwards 10 | // - 11 | 12 | struct GlobalState; // global state from GUI 13 | 14 | namespace glTFx { 15 | 16 | class TFxHairStrands; 17 | 18 | class TFxSimulation { 19 | public: 20 | TFxSimulation(); 21 | ~TFxSimulation(); 22 | 23 | void start_simulation(double fTime, std::vector&); 24 | void wait_on_simulation(); 25 | 26 | 27 | private: 28 | 29 | // original AMD lib 30 | TressFXSimulation mSimulation; 31 | 32 | // TODO pack in struct SimulationShaders 33 | glUtils::Shader shader_sim0_IntegrationAndGlobalShapeConstraints; 34 | glUtils::Shader shader_sim1_VelocityShockPropagation; 35 | glUtils::Shader shader_sim2_LocalShapeConstraints; 36 | glUtils::Shader shader_sim3_LengthConstraintsWindAndCollision; 37 | glUtils::Shader shader_sim4_UpdateFollowHairVertices; 38 | 39 | }; 40 | 41 | } // namespace glTFx 42 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/_utils.glsl: -------------------------------------------------------------------------------- 1 | #define CONCAT(a, b) a ## b 2 | 3 | #define STRUCTURED_BUFFER(BINDING, TYPE, INTROSPECT_NAME) \ 4 | layout(std430, binding=BINDING) \ 5 | buffer INTROSPECT_NAME { \ 6 | TYPE CONCAT(INTROSPECT_NAME, _)[]; \ 7 | }; 8 | 9 | // all values in [0-1] 10 | // @see http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl 11 | vec3 rgb2hsv(vec3 c) { 12 | vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); 13 | vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy); 14 | vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx); 15 | 16 | float d = q.x - min(q.w, q.y); 17 | float e = 1.0e-10; 18 | return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); 19 | } 20 | 21 | // all values in [0-1] 22 | // @see http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl 23 | vec3 hsv2rgb(vec3 c) { 24 | vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); 25 | vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); 26 | return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); 27 | } 28 | 29 | const float GAMMA = 2.2; 30 | 31 | vec3 tonemapReinhard (vec3 color) { 32 | return color / (color + vec3(1.0)); 33 | } 34 | 35 | vec3 gammaFix (vec3 color, float gamma) { 36 | return pow(color, vec3(1.0/gamma)); 37 | } 38 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/lib/TressFXRendering.coverage.glsl: -------------------------------------------------------------------------------- 1 | // START TressFXRendering.coverage 2 | 3 | // Calculate the pixel coverage of a hair strand by computing the hair width 4 | // p0, p1, pixelLoc are in d3d clip space (-1 to 1)x(-1 to 1) 5 | // 6 | // @param vec2 p0 - position of 'left' vertex after perspective projection 7 | // @param vec2 p1 - position of 'right' vertex after perspective projection 8 | float ComputeCoverage(vec2 p0, vec2 p1, vec2 pixelLoc, vec2 winSize) { 9 | // Scale positions so 1.f = half pixel width 10 | p0 *= winSize; 11 | p1 *= winSize; 12 | 13 | float p0dist = length(p0 - pixelLoc); 14 | float p1dist = length(p1 - pixelLoc); 15 | float hairWidth = length(p0 - p1); 16 | 17 | // if outside, set sign to -1, else set sign to 1 18 | float sign = (p0dist < hairWidth || p1dist < hairWidth) ? -1 : 1; 19 | 20 | // signed distance (positive if inside hair, negative if outside hair) 21 | float relDist = sign * clamp(min(p0dist, p1dist), 0, 1); 22 | 23 | // returns coverage based on the relative distance 24 | // 0, if completely outside hair edge 25 | // 1, if completely inside hair edge 26 | return (relDist + 1.f) * 0.5f; 27 | } 28 | 29 | 30 | // END TressFXRendering.coverage 31 | -------------------------------------------------------------------------------- /cmake/Modules/FindGLAD.cmake: -------------------------------------------------------------------------------- 1 | # Defines on success: 2 | # GLAD_INCLUDE_DIRS - where to find SDL2/SDL.h 3 | # GLAD_FOUND - if the library was successfully located 4 | # GLAD_LIBRARY - the name of the library to link against 5 | # 6 | # Parameters: 7 | # GLAD_ROOT_DIR - root directory of a GLAD installation 8 | 9 | IF(M_OS_LINUX) 10 | SET(_glad_SEARCH_DIRS "/usr" "/usr/local") 11 | ENDIF() 12 | 13 | # Put user specified location at beginning of search 14 | IF(GLAD_ROOT_DIR) 15 | SET(_glad_SEARCH_DIRS "${GLAD_ROOT_DIR}" ${_glad_SEARCH_DIRS}) 16 | ENDIF() 17 | 18 | # Locate header 19 | FIND_PATH(GLAD_INCLUDE_DIRS "glad/glad.h" 20 | PATH_SUFFIXES "include" 21 | HINTS $ENV{GLAD_ROOT_DIR} 22 | PATHS ${_glad_SEARCH_DIRS}) 23 | 24 | # Locate libraries 25 | FIND_LIBRARY(GLAD_LIBRARY 26 | NAMES GLAD 27 | PATH_SUFFIXES lib64 lib 28 | HINTS $ENV{GLAD_ROOT_DIR} 29 | PATHS ${_glad_SEARCH_DIRS} 30 | ) 31 | 32 | # Handle REQUIRED argument, define *_FOUND variable 33 | INCLUDE(FindPackageHandleStandardArgs) 34 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLAD DEFAULT_MSG 35 | GLAD_INCLUDE_DIRS GLAD_LIBRARY) 36 | 37 | IF(GLAD_FOUND) 38 | MESSAGE(STATUS "GLAD_INCLUDE_DIRS = ${GLAD_INCLUDE_DIRS}") 39 | MESSAGE(STATUS "GLAD_LIBRARY = ${GLAD_LIBRARY}") 40 | ENDIF() 41 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/sim/_SimCapsuleCollision.comp.glsl: -------------------------------------------------------------------------------- 1 | // START _SimCapsuleCollision.glsl 2 | 3 | const int NUM_COLLISION_CAPSULES = 4; 4 | 5 | uniform vec4 g_Capsules[4]; 6 | 7 | bool CapsuleCollision(vec4 curPosition, inout vec3 newPosition, vec4 capsule) { 8 | const float radius1 = capsule.w; 9 | newPosition = curPosition.xyz; 10 | 11 | if (!IsMovable(curPosition)) { 12 | return false; 13 | } 14 | 15 | vec3 delta1 = capsule.xyz - curPosition.xyz; 16 | if (dot(delta1, delta1) < radius1 * radius1) { 17 | vec3 n = normalize(-delta1); 18 | newPosition = radius1 * n + capsule.xyz; // :( 19 | return true; 20 | } 21 | 22 | return false; 23 | } 24 | 25 | // Resolve hair vs capsule collisions. To use this, 26 | // set TRESSFX_COLLISION_CAPSULES to 1 27 | bool ResolveCapsuleCollisions(inout vec4 curPosition, vec4 oldPos) { 28 | bool bAnyColDetected = false; 29 | 30 | #if TRESSFX_COLLISION_CAPSULES 31 | vec3 newPos; 32 | 33 | for (int i = 0; i < NUM_COLLISION_CAPSULES; i++) { 34 | bool bColDetected = CapsuleCollision(curPosition, newPos, g_Capsules[i]); 35 | 36 | if (bColDetected) { 37 | curPosition.xyz = newPos; 38 | } 39 | 40 | bAnyColDetected = bColDetected ? true : bAnyColDetected; 41 | } 42 | #endif 43 | 44 | return bAnyColDetected; 45 | } 46 | 47 | 48 | // END _SimCapsuleCollision.glsl 49 | -------------------------------------------------------------------------------- /libs/imgui/imgui_impl_opengl3.h: -------------------------------------------------------------------------------- 1 | // ImGui Renderer for: OpenGL3 (modern OpenGL with shaders / programmatic pipeline) 2 | // This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) 3 | // (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..) 4 | 5 | // Implemented features: 6 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. 7 | 8 | // About GLSL version: 9 | // The 'glsl_version' initialization parameter defaults to "#version 150" if NULL. 10 | // Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure! 11 | 12 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = "#version 150"); 13 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); 14 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); 15 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); 16 | 17 | // Called by Init/NewFrame/Shutdown 18 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); 19 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); 20 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); 21 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); 22 | -------------------------------------------------------------------------------- /cmake/Modules/FindGLM.cmake: -------------------------------------------------------------------------------- 1 | # Defines on success: 2 | # GLM_INCLUDE_DIRS - where to find glm/glm.hpp 3 | # GLM_FOUND - if the library was successfully located 4 | # 5 | # Parameters: 6 | # GLM_ROOT_DIR - root directory of a glm installation 7 | # Headers are expected to be found in either: 8 | # /glm/glm.hpp OR 9 | # /include/glm/glm.hpp 10 | # This variable can either be a cmake or environment 11 | # variable. 12 | 13 | # Based on https://github.com/Groovounet/glm-deprecated/blob/master/util/FindGLM.cmake 14 | 15 | IF(M_OS_LINUX) 16 | SET(_glm_HEADER_SEARCH_DIRS "/usr/include" "/usr/local/include") 17 | ENDIF() 18 | 19 | # Put user specified location at beginning of search 20 | IF(GLM_ROOT_DIR) 21 | SET(_glm_HEADER_SEARCH_DIRS "${GLM_ROOT_DIR}" ${_glm_HEADER_SEARCH_DIRS}) 22 | ENDIF() 23 | 24 | # Locate header 25 | FIND_PATH(GLM_INCLUDE_DIRS "glm/glm.hpp" 26 | PATH_SUFFIXES "include" 27 | HINTS $ENV{GLAD_ROOT_DIR} 28 | PATHS ${_glm_HEADER_SEARCH_DIRS}) 29 | 30 | # Handle REQUIRD argument, define *_FOUND variable 31 | INCLUDE(FindPackageHandleStandardArgs) 32 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLM DEFAULT_MSG 33 | GLM_INCLUDE_DIRS) 34 | 35 | IF(GLM_FOUND) 36 | MESSAGE(STATUS "GLM_INCLUDE_DIRS = ${GLM_INCLUDE_DIRS}") 37 | ENDIF() -------------------------------------------------------------------------------- /src/gl-utils/buffer/read.impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static u32 calculate_read_range(const glUtils::RawBuffer& buf, const glUtils::BufferRange range_bytes_, void*const out_ptr) { 4 | GFX_FAIL_IF(!buf.is_created(), "Tried to read ", range_bytes_.size(), " bytes from deleted buffer"); 5 | GFX_FAIL_IF(out_ptr == nullptr, "Tried to read data into nullptr. You probably wanted to read into allocated buffer"); 6 | 7 | i32 size_left = buf.bytes - range_bytes_.offset(), 8 | bytes_to_read = std::min(size_left, (i32) range_bytes_.size()); 9 | 10 | GFX_FAIL_IF(size_left < 1, "Tried to read at offset ", range_bytes_.offset(), ", but buffer has only ", buf.bytes, " bytes"); 11 | GFX_FAIL_IF(bytes_to_read < 1, "Tried to read ", bytes_to_read, " bytes. You probably wanted to read >0 bytes"); 12 | 13 | return bytes_to_read; 14 | } 15 | 16 | namespace glUtils { 17 | 18 | u32 read (const RawBuffer& buf, const BufferRange range_bytes_, void*const out_ptr) { 19 | BufferRange range_bytes = { 20 | range_bytes_.offset(), 21 | calculate_read_range(buf, range_bytes_, out_ptr) 22 | }; 23 | if (range_bytes.size() == 0) { 24 | return 0; 25 | } 26 | 27 | if (buf.is_persistent_mapping()) { 28 | GFX_FAIL("Reading persistently mapped buffers is not supported ATM"); 29 | } else { 30 | GFX_GL_CALL(glGetNamedBufferSubData, buf.gl_id, range_bytes.offset(), range_bytes.size(), out_ptr); 31 | } 32 | 33 | return range_bytes.size(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /libs/imgui/imgui_impl_sdl.h: -------------------------------------------------------------------------------- 1 | // ImGui Platform Binding for: SDL2 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | // (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) 4 | 5 | // Implemented features: 6 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 7 | // [X] Platform: Clipboard support. 8 | // Missing features: 9 | // [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME. 10 | 11 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 12 | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). 13 | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. 14 | // https://github.com/ocornut/imgui 15 | 16 | struct SDL_Window; 17 | typedef union SDL_Event SDL_Event; 18 | 19 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); 20 | IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); 21 | IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown(); 22 | IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(SDL_Window* window); 23 | IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(SDL_Event* event); 24 | -------------------------------------------------------------------------------- /include/gl-utils/uniform.types.hpp: -------------------------------------------------------------------------------- 1 | 2 | UNIFORM_MACRO(i32, GL_INT, glUniform1iv, &v) 3 | UNIFORM_MACRO(u32, GL_UNSIGNED_INT, glUniform1uiv, &v) 4 | UNIFORM_MACRO(f32, GL_FLOAT, glUniform1fv, &v) 5 | UNIFORM_MACRO(glm::vec2, GL_FLOAT_VEC2, glUniform2fv, glm::value_ptr(v)) 6 | UNIFORM_MACRO(glm::ivec2, GL_INT_VEC2, glUniform2iv, glm::value_ptr(v)) 7 | UNIFORM_MACRO(glm::uvec2, GL_UNSIGNED_INT_VEC2, glUniform2uiv, glm::value_ptr(v)) 8 | UNIFORM_MACRO(glm::vec3, GL_FLOAT_VEC3, glUniform3fv, glm::value_ptr(v)) 9 | UNIFORM_MACRO(glm::ivec3, GL_INT_VEC3, glUniform3iv, glm::value_ptr(v)) 10 | UNIFORM_MACRO(glm::uvec3, GL_UNSIGNED_INT_VEC3, glUniform3uiv, glm::value_ptr(v)) 11 | UNIFORM_MACRO(glm::vec4, GL_FLOAT_VEC4, glUniform4fv, glm::value_ptr(v)) 12 | UNIFORM_MACRO(glm::ivec4, GL_INT_VEC4, glUniform4iv, glm::value_ptr(v)) 13 | UNIFORM_MACRO(glm::uvec4, GL_UNSIGNED_INT_VEC4, glUniform4uiv, glm::value_ptr(v)) 14 | 15 | #ifndef UNIFY_UNIFORM_MACRO 16 | // matrices 17 | UNIFORM_MACRO_MAT(glm::mat2, GL_FLOAT_MAT2, glUniformMatrix2fv, glm::value_ptr(v)) 18 | UNIFORM_MACRO_MAT(glm::mat3, GL_FLOAT_MAT3, glUniformMatrix3fv, glm::value_ptr(v)) 19 | UNIFORM_MACRO_MAT(glm::mat4, GL_FLOAT_MAT4, glUniformMatrix4fv, glm::value_ptr(v)) 20 | #else 21 | UNIFORM_MACRO(glm::mat2, GL_FLOAT_MAT2, glUniformMatrix2fv, glm::value_ptr(v)) 22 | UNIFORM_MACRO(glm::mat3, GL_FLOAT_MAT3, glUniformMatrix3fv, glm::value_ptr(v)) 23 | UNIFORM_MACRO(glm::mat4, GL_FLOAT_MAT4, glUniformMatrix4fv, glm::value_ptr(v)) 24 | #endif 25 | -------------------------------------------------------------------------------- /src/gl-utils/buffer/copy_to.impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static i32 min_3(i32 a, i32 b, i32 c) { 4 | return std::min(a, std::min(b, c)); 5 | } 6 | 7 | static u32 calculate_copy_range( 8 | const glUtils::RawBuffer& src, const glUtils::RawBuffer& dest, 9 | const glUtils::BufferRange src_range_, const u32 dest_offset) 10 | { 11 | i32 size_left_src = src.bytes - src_range_.offset(), 12 | size_left_dest = dest.bytes - dest_offset, 13 | bytes_to_copy = min_3(size_left_src, size_left_dest, (i32)src_range_.size()); 14 | 15 | GFX_FAIL_IF(!src.is_created(), "Tried to copy ", src_range_.size(), " bytes from deleted buffer"); 16 | GFX_FAIL_IF(!dest.is_created(), "Tried to copy ", src_range_.size(), " bytes into deleted buffer"); 17 | GFX_FAIL_IF(size_left_src < 1, "Tried to copy ", src_range_.size(), " bytes from source at offset ", 18 | src_range_.offset(), ", but buffer has only ", src.bytes, " bytes"); 19 | GFX_FAIL_IF(size_left_dest < 1, "Tried to copy ", src_range_.size(), 20 | " bytes into destination buffer at offset ", dest_offset, ", but buffer has only ", dest.bytes, " bytes"); 21 | GFX_FAIL_IF(bytes_to_copy < 1, "Tried to copy ", bytes_to_copy, 22 | " bytes between buffers. You probably wanted to copy >0 bytes"); 23 | 24 | return (u32) bytes_to_copy; 25 | } 26 | 27 | namespace glUtils { 28 | 29 | u32 copy_to(const RawBuffer& src, const RawBuffer& dest, const BufferRange src_range_, const u32 dest_offset) { 30 | const BufferRange copy_range = { 31 | src_range_.offset(), 32 | calculate_copy_range(src, dest, src_range_, dest_offset) 33 | }; 34 | 35 | if (copy_range.size() == 0) { 36 | return 0; 37 | } 38 | 39 | GFX_GL_CALL(glCopyNamedBufferSubData, 40 | src.gl_id, dest.gl_id, 41 | copy_range.offset(), dest_offset, copy_range.size()); 42 | 43 | return copy_range.size(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /cmake/Modules/FindSDL2.cmake: -------------------------------------------------------------------------------- 1 | # Defines on success: 2 | # SDL2_INCLUDE_DIRS - where to find SDL2/SDL.h 3 | # SDL2_FOUND - if the library was successfully located 4 | # SDL2_LIBRARY - the name of the library to link against 5 | # 6 | # Parameters: 7 | # SDL2_ROOT_DIR - root directory of a SDL2 installation 8 | 9 | # Based on: 10 | # - https://github.com/brendan-w/collector/blob/master/cmake/FindSDL2.cmake 11 | # - https://github.com/tcbrindle/sdl2-cmake-scripts/blob/master/FindSDL2.cmake 12 | 13 | IF(M_OS_LINUX) 14 | SET(_sdl2_SEARCH_DIRS "/usr" "/usr/local") 15 | ENDIF() 16 | 17 | # Put user specified location at beginning of search 18 | IF(SDL2_ROOT_DIR) 19 | SET(_sdl2_SEARCH_DIRS "${SDL2_ROOT_DIR}" ${_sdl2_SEARCH_DIRS}) 20 | ENDIF() 21 | 22 | # Locate header 23 | FIND_PATH(SDL2_INCLUDE_DIRS "SDL2/SDL.h" 24 | PATH_SUFFIXES "include" 25 | HINTS $ENV{SDL2_ROOT_DIR} 26 | PATHS ${_sdl2_SEARCH_DIRS}) 27 | 28 | # Locate libraries: SDL2 & SDL2main 29 | FIND_LIBRARY(SDL2_LIBRARY_DIR 30 | NAMES SDL2 31 | PATH_SUFFIXES lib64 lib 32 | HINTS $ENV{SDL2_ROOT_DIR} 33 | PATHS ${_sdl2_SEARCH_DIRS} 34 | ) 35 | FIND_LIBRARY(SDL2MAIN_LIBRARY 36 | NAMES SDL2main 37 | PATH_SUFFIXES lib64 lib 38 | HINTS $ENV{SDL2_ROOT_DIR} 39 | PATHS ${_sdl2_SEARCH_DIRS} 40 | ) 41 | 42 | SET(SDL2_LIBRARY ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_DIR} ${SDL2_LIBRARY}) 43 | 44 | # mingw requires additional prepended library: mingw32 45 | IF(MINGW) 46 | SET(SDL2_LIBRARY mingw32 ${SDL2_LIBRARY}) 47 | ENDIF() 48 | 49 | 50 | # Handle REQUIRED argument, define *_FOUND variable 51 | INCLUDE(FindPackageHandleStandardArgs) 52 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 DEFAULT_MSG 53 | SDL2_INCLUDE_DIRS SDL2MAIN_LIBRARY SDL2_LIBRARY_DIR) 54 | 55 | IF(SDL2_FOUND) 56 | MESSAGE(STATUS "SDL2_INCLUDE_DIRS = ${SDL2_INCLUDE_DIRS}") 57 | MESSAGE(STATUS "SDL2_LIBRARY = ${SDL2_LIBRARY}") 58 | ENDIF() 59 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/TressFXBoneSkeletonInterface.h: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // TressFXSkeletonInterface is optionally used to remap bones to engine ordering 3 | // if it differs from Maya. 4 | // 5 | // An implementation of this inteface is used in TressFXAsset::LoadHairData 6 | // ---------------------------------------------------------------------------- 7 | // 8 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | // THE SOFTWARE. 27 | // 28 | 29 | #pragma once 30 | 31 | class TressFXSkeletonInterface 32 | { 33 | public: 34 | virtual unsigned int GetBoneIndexByName(const char* pBoneName) const = 0; 35 | virtual const char* GetBoneNameByIndex(unsigned int index) const = 0; 36 | virtual unsigned int GetNumberOfBones() const = 0; 37 | }; -------------------------------------------------------------------------------- /cmake/Config.cmake: -------------------------------------------------------------------------------- 1 | # OS 2 | if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") 3 | set(M_OS_WINDOWS 1) 4 | elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") 5 | set(M_OS_UNIX 1) 6 | set(M_OS_LINUX 1) 7 | else() 8 | message(FATAL_ERROR "Unsupported operating system") 9 | return() 10 | endif() 11 | 12 | # ARCHITECTURE (note: this test won't work for cross-compilation) 13 | include(CheckTypeSize) 14 | check_type_size(void* SIZEOF_VOID_PTR) 15 | if("${SIZEOF_VOID_PTR}" STREQUAL "4") 16 | set(ARCH_32BITS 1) 17 | set(M_ARCH_NAME "32bit") 18 | elseif("${SIZEOF_VOID_PTR}" STREQUAL "8") 19 | set(ARCH_64BITS 1) 20 | set(M_ARCH_NAME "64bit") 21 | else() 22 | message(FATAL_ERROR "Unsupported architecture") 23 | return() 24 | endif() 25 | 26 | # COMPILER 27 | if(CMAKE_CXX_COMPILER MATCHES ".*clang[+][+]" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 28 | execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "--version" OUTPUT_VARIABLE CLANG_VERSION_OUTPUT) 29 | string(REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+).*" "\\1" M_CLANG_VERSION "${CLANG_VERSION_OUTPUT}") 30 | set(M_COMPILER_NAME "clang ${M_CLANG_VERSION}") 31 | set(M_CPP_17_COMPILER_FLAG "-std=c++1z -Wc++1z-extensions") 32 | elseif(CMAKE_COMPILER_IS_GNUCXX) 33 | execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "-dumpversion" OUTPUT_VARIABLE GCC_VERSION_OUTPUT) 34 | string(REGEX REPLACE "([0-9]+\\.[0-9]+).*" "\\1" M_GCC_VERSION "${GCC_VERSION_OUTPUT}") 35 | execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "--version" OUTPUT_VARIABLE GCC_COMPILER_VERSION) 36 | string(REGEX MATCHALL ".*(tdm[64]*-[1-9]).*" M_COMPILER_GCC_TDM "${GCC_COMPILER_VERSION}") 37 | execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "-dumpmachine" OUTPUT_VARIABLE GCC_MACHINE) 38 | string(STRIP "${GCC_MACHINE}" GCC_MACHINE) 39 | 40 | set(M_COMPILER_NAME "g++ ${GCC_VERSION_OUTPUT}") 41 | set(M_CPP_17_COMPILER_FLAG "-std=c++1z") 42 | else() 43 | message(FATAL_ERROR "Unsupported compiler") 44 | return() 45 | endif() 46 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/ppll_resolve.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | // #define TAIL_COMPRESS 1 4 | 5 | #pragma include "_utils.glsl" 6 | // #pragma include "lib/TressFXRendering.shading.glsl" 7 | #pragma include "lib/TressFXPPLL.glsl" 8 | #pragma include "lib/TressFXPPLL.resolve.glsl" // uses TressFXRendering.shading 9 | 10 | 11 | // START ppll_resolve.frag 12 | // (main) 13 | 14 | uniform vec3 g_vEye; 15 | 16 | const int RENDER_MODE_FILL_ONE_COLOR = 1; 17 | const int RENDER_MODE_PPLL_DEPTH = 2; 18 | uniform int g_RenderMode; 19 | 20 | out vec4 ps_outputColor; 21 | 22 | layout(early_fragment_tests) in; // [earlydepthstencil] 23 | 24 | 25 | // 26 | const float MAX_DEBUG_LIST_DEPTH = 8; 27 | const vec3 DEBUG_LIST_0 = vec3(0,0,1); 28 | const vec3 DEBUG_LIST_1 = vec3(1,0,0); 29 | 30 | uint debug_count_list_len (vec2 vfScreenAddress) { 31 | uint result = 0; 32 | uint pointer = imageLoad(tFragmentListHead, ivec2(vfScreenAddress)).r; 33 | uint iter = 0; 34 | 35 | while (pointer != FRAGMENT_LIST_NULL && iter < MAX_DEBUG_LIST_DEPTH) { 36 | pointer = NODE_NEXT(pointer); 37 | ++result; 38 | ++iter; 39 | } 40 | 41 | return result; 42 | } 43 | // 44 | 45 | 46 | void main () { 47 | // we could split the shaders into 3. Or we can shamelessly 'if' 48 | 49 | if (g_RenderMode == RENDER_MODE_FILL_ONE_COLOR) { 50 | ps_outputColor = vec4(1,1,0,1); 51 | } else if (g_RenderMode == RENDER_MODE_PPLL_DEPTH) { 52 | uint depth = debug_count_list_len(gl_FragCoord.xy); 53 | float fac = clamp(float(depth) / MAX_DEBUG_LIST_DEPTH, 0, 1); 54 | ps_outputColor = vec4(mix(DEBUG_LIST_0, DEBUG_LIST_1, fac), 1); 55 | } else { 56 | vec4 color = GatherLinkedList(gl_FragCoord.xy); 57 | // ps_outputColor = vec4(gammaFix(tonemapReinhard(color.rgb), GAMMA), color.a); 58 | // ps_outputColor = vec4(gammaFix(color.rgb, GAMMA), color.a); 59 | ps_outputColor = vec4(color.rgb, color.a); 60 | } 61 | } 62 | 63 | 64 | // unroll K-buffer 65 | /* 66 | 67 | */ 68 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/sim4_UpdateFollowHairVertices.comp.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | #pragma include "_utils.glsl" 4 | #pragma include "sim/_SimParams.comp.glsl" 5 | #pragma include "sim/_SimCommon.comp.glsl" 6 | #pragma include "sim/_SimBuffers.comp.glsl" 7 | 8 | uniform float g_FollowHairRootOffsetMultiplier; 9 | 10 | shared vec4 sharedPos[THREAD_GROUP_SIZE]; 11 | shared vec4 sharedTangent[THREAD_GROUP_SIZE]; 12 | 13 | // Generate follow (child) hair strands from guide (master) strands. 14 | // 15 | // One thread computes one vertex (of the guide-hair). 16 | // 17 | layout (local_size_x = THREAD_GROUP_SIZE) in; // [numthreads(THREAD_GROUP_SIZE, 1, 1)] 18 | void main() { 19 | uint numVerticesInTheStrand; // 32 20 | PerVertexData vertData = GetPerVertexData(gl_LocalInvocationIndex, gl_WorkGroupID.x, numVerticesInTheStrand); 21 | 22 | // copy before we modify it 23 | sharedPos[vertData.localId] = g_HairVertexPositions_[vertData.vertexId_global]; 24 | sharedTangent[vertData.localId] = g_HairVertexTangents_[vertData.vertexId_global]; 25 | GroupMemoryBarrierWithGroupSync(); 26 | 27 | for (uint i = 0; i < g_NumFollowHairsPerGuideHair; i++) { 28 | uint globalFollowVertexIndex = vertData.vertexId_global + numVerticesInTheStrand * (i + 1); 29 | uint globalFollowStrandIndex = vertData.strandId_global + i + 1; 30 | 31 | // we can spread follow-hairs more using g_TipSeparationFactor simulation param 32 | float lenFromRoot = float(vertData.vertexId) / float(numVerticesInTheStrand); // in [0,1] 33 | float factor = g_TipSeparationFactor * lenFromRoot + 1.0f; 34 | // delta from guide-hair 35 | vec3 offset = factor * g_FollowHairRootOffset_[globalFollowStrandIndex].xyz * g_FollowHairRootOffsetMultiplier; 36 | vec3 followPos = sharedPos[vertData.localId].xyz + offset; 37 | 38 | // write back 39 | g_HairVertexPositions_[globalFollowVertexIndex].xyz = followPos; 40 | g_HairVertexTangents_[globalFollowVertexIndex] = sharedTangent[vertData.localId]; 41 | } 42 | 43 | return; 44 | } 45 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/lib/TressFXPPLL.build.glsl: -------------------------------------------------------------------------------- 1 | // START TressFXPPLL.build.glsl 2 | 3 | // 2D texture to store head pointers 4 | // RWTexture2D tRWFragmentListHead; 5 | layout(location=1, r32ui) // why location, not binding? everyone uses binding, but location seems to be correct 6 | uniform uimage2D tRWFragmentListHead; 7 | 8 | // SSBO to store nodes 9 | // RWStructuredBuffer LinkedListUAV; 10 | STRUCTURED_BUFFER(0, PPLL_STRUCT , LinkedListUAV) 11 | layout(binding=0, offset=0) uniform atomic_uint LinkedListUAV_counter; 12 | 13 | // size of LinkedListUAV 14 | // width * height * AVE_FRAGS_PER_PIXEL(4) 15 | uniform int nNodePoolSize; 16 | 17 | // Allocate a new fragment location in fragment color, depth, and link buffers 18 | uint AllocateFragment(ivec2 vScreenAddress) { 19 | uint newAddress = atomicCounterIncrement(LinkedListUAV_counter); //LinkedListUAV.IncrementCounter(); 20 | if (newAddress <= 0 || newAddress > nNodePoolSize){ 21 | newAddress = FRAGMENT_LIST_NULL; 22 | } 23 | return newAddress; 24 | } 25 | 26 | // Insert a new fragment at the head of the list. The old list head becomes the 27 | // the second fragment in the list and so on. Return the address of the *old* head. 28 | uint MakeFragmentLink(ivec2 vScreenAddress, uint nNewHeadAddress) { 29 | // int nOldHeadAddress; 30 | // InterlockedExchange(tRWFragmentListHead[vScreenAddress], nNewHeadAddress, nOldHeadAddress); 31 | uint nOldHeadAddress = imageAtomicExchange(tRWFragmentListHead, vScreenAddress, nNewHeadAddress); 32 | return nOldHeadAddress; 33 | } 34 | 35 | 36 | // Write fragment attributes to list location. 37 | void WriteFragmentAttributes(uint nAddress, uint nPreviousLink, vec4 vData, vec3 vColor3, float fDepth) { 38 | LinkedListUAV_[nAddress].data = PackFloat4IntoUint(vData); 39 | LinkedListUAV_[nAddress].color = PackFloat4IntoUint(vec4(vColor3, 0)); 40 | LinkedListUAV_[nAddress].depth = uint(fDepth * 255.0); //uint(saturate(fDepth)); or gl_FragCoord.z; ? 41 | LinkedListUAV_[nAddress].uNext = nPreviousLink; 42 | } 43 | 44 | // END TressFXPPLL.build.glsl 45 | -------------------------------------------------------------------------------- /libs/amd_tressfx/src/TressFXEngineInterface.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // Calls into engine for non-graphics items: error reporting, memory allocation, ... 3 | //------------------------------------------------------------------------------------- 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | #pragma once 27 | 28 | 29 | 30 | #include "AMD_TressFX.h" 31 | 32 | 33 | 34 | #ifndef TRESSFX_ASSERT 35 | #include 36 | #define TRESSFX_ASSERT assert 37 | #endif 38 | 39 | #define EI_Malloc(x) (AMD::g_Callbacks.pfMalloc(x)) //malloc(x); 40 | #define EI_Free(x) (AMD::g_Callbacks.pfFree(x)) 41 | 42 | #define TressFXLogWarning(msg) (AMD::g_Callbacks.pfError(msg)) 43 | 44 | 45 | #define EI_Read AMD::g_Callbacks.pfRead 46 | #define EI_Seek AMD::g_Callbacks.pfSeek 47 | 48 | 49 | #ifndef EI_Safe_Free 50 | #define EI_Safe_Free(x) { if(NULL != (x)) { EI_Free(x); (x)=NULL;} } 51 | #endif 52 | -------------------------------------------------------------------------------- /src/State.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gl-tfx/TFxSettings.hpp" 4 | 5 | struct Camera { 6 | const float camera_distance_sensitivity = 0.1f; 7 | const float camera_sensitivity = 0.005f; 8 | const float zNear = 0.1f; 9 | const float zFar = 50.0f; 10 | const float fov_dgr = 45.0f; 11 | 12 | // glm::vec3 cam_pos = {0,0,2}; 13 | // glm::vec3 cam_target = {0,0,0}; 14 | float camera_distance = 2.0f; 15 | glm::vec2 angles = {0,0}; 16 | 17 | glm::mat4 view; 18 | glm::mat4 projection; 19 | 20 | glm::vec3 get_position () const noexcept; 21 | }; 22 | 23 | /** 24 | * Overall state of the program. Mainly used with imgui for debug 25 | */ 26 | struct GlobalState { 27 | // init 28 | const u32 win_width = 1280; 29 | const u32 win_height = 720; 30 | inline float aspect_ratio () const noexcept {return this->win_width * 1.0f / this->win_height; } 31 | const std::string title = "TressFX"; 32 | GLuint dummy_vao = 0; // for when we have to bind vao, but values does not matter 33 | 34 | // TFx 35 | glTFx::TFxSettings tfx_settings; 36 | bool show_collision_capsules = false; 37 | 38 | // scene 39 | const std::string obj_vs = "src/shaders/simple_obj.vert.glsl"; 40 | const std::string obj_fs = "src/shaders/simple_obj.frag.glsl"; 41 | bool show_model = true; 42 | 43 | 44 | // background 45 | const std::string bg_vs = "src/shaders/bg.vert.glsl"; 46 | const std::string bg_fs = "src/shaders/bg.frag.glsl"; 47 | const glm::vec4 bg_grad_top = {0.49, 0.57, 0.65, 1.0}; // some nice gray-blue color 48 | const glm::vec4 bg_grad_bottom = {0.01, 0.01, 0.01, 1.0}; 49 | 50 | // camera 51 | Camera camera; 52 | 53 | // runtime 54 | bool running = true; 55 | 56 | // draw params 57 | glUtils::DrawParameters draw_params; 58 | inline void update_draw_params (const glUtils::DrawParameters& new_parms) noexcept { 59 | glUtils::apply_draw_parameters(new_parms, &this->draw_params); 60 | this->draw_params = new_parms; 61 | } 62 | 63 | // ui tests 64 | bool test_bool = false; 65 | float test_float = 0.45f; 66 | int test_counter = 0; 67 | glm::vec4 test_vec4 = {0.45f, 0.55f, 0.60f, 1.00f}; 68 | }; 69 | -------------------------------------------------------------------------------- /src/gl-tfx/GpuInterface/buffer.impl.hpp: -------------------------------------------------------------------------------- 1 | static void assert_is_memory_buffer(const EI_Resource& res) { 2 | bool is_counter_buf = res.type == TFx_ResourceType::StructuredBufferRW_WithAtomicCounter; 3 | bool is_buff = res.type == TFx_ResourceType::StructuredBufferRW 4 | || res.type == TFx_ResourceType::StructuredBufferR; 5 | GFX_FAIL_IF(is_counter_buf, "Memory mapping buffer with counter!" 6 | " This could get complicated, implement when know circumstances."); 7 | GFX_FAIL_IF(!is_buff, "Tried to map/unmap/copy resource that is not a buffer"); 8 | } 9 | 10 | void TFx_cbCopy(EI_CommandContextRef pContext, EI_StructuredBuffer& from, EI_StructuredBuffer& to) { 11 | GFX_FAIL("TFx_cbCopy"); 12 | } 13 | 14 | // Map gets a pointer to upload heap / mapped memory. 15 | // Unmap issues the copy. 16 | // This is only ever used for the initial upload. 17 | // 18 | void* TFx_cbMap(EI_CommandContextRef pContext, EI_StructuredBuffer& sb) { 19 | assert_is_memory_buffer(sb); 20 | LOGD << "[TFx_cbMap] mapping: '" << sb.name << "' (bytes=" << sb.buffer.bytes << ")"; 21 | return glMapNamedBuffer(sb.buffer.gl_id, GL_READ_WRITE); 22 | } 23 | 24 | bool TFx_cbUnmap(EI_CommandContextRef pContext, EI_StructuredBuffer& sb) { 25 | assert_is_memory_buffer(sb); 26 | LOGD << "[TFx_cbMap] UN_mapping: '" << sb.name << "'"; 27 | return glUnmapNamedBuffer(sb.buffer.gl_id); 28 | } 29 | 30 | /* 31 | void SuCopy(EI_CommandContextRef pContext, EI_StructuredBuffer& from, EI_StructuredBuffer& to) { 32 | (void)pContext; 33 | to.resource->CopyResource(*from.resource); 34 | } 35 | 36 | // Map gets a pointer to upload heap / mapped memory. 37 | // Unmap issues the copy. 38 | // This is only ever used for the initial upload. 39 | // 40 | void* SuMap(EI_CommandContextRef pContext, EI_StructuredBuffer& sb) { 41 | SU_ASSERT(sb.resource->GetType() == SuGPUResource::GPU_RESOURCE_BUFFER); 42 | SuGPUBuffer* pBuffer = static_cast(sb.resource.get()); 43 | SuHandle handle = pBuffer->Map(SuGPUResource::MAP_WRITE_DISCARD); 44 | return (void*)handle; 45 | } 46 | 47 | bool SuUnmap(EI_CommandContextRef pContext, EI_StructuredBuffer& sb) { 48 | return sb.resource->Unmap(); 49 | } 50 | */ 51 | -------------------------------------------------------------------------------- /include/logging/Logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // NOTE: NOT THREAD SAFE! 6 | // NOTE: written long, long time ago, very crappy! 7 | 8 | #define MIN_LOG_LEVEL logger::Trace 9 | 10 | #define LOG(lvl)\ 11 | if (lvl < MIN_LOG_LEVEL){}\ 12 | else if(lvl < logger::Log::ReportingLevel) {} \ 13 | else logger::Log().get( __FILE__, __LINE__, lvl) 14 | // else logger::Log().get( __FILE__, __LINE__, lvl).get_stream() 15 | 16 | #define LOGT LOG(logger::Trace) 17 | #define LOGD LOG(logger::Debug) 18 | #define LOGI LOG(logger::Info) 19 | #define LOGW LOG(logger::Warning) 20 | #define LOGE LOG(logger::Error) 21 | 22 | namespace logger { 23 | 24 | class LogImpl; 25 | 26 | enum LogLevel { 27 | Trace = 0, 28 | Debug = 1, 29 | Info = 2, 30 | Warning = 3, 31 | Error = 4 32 | }; 33 | 34 | class Log { 35 | public: 36 | static LogLevel ReportingLevel; 37 | 38 | Log(); 39 | ~Log(); 40 | 41 | LogImpl& get(const char* const file, const int line, LogLevel level); 42 | 43 | protected: 44 | LogImpl* impl; // ugh, PIMPL logger! TODO placement new? 45 | 46 | private: 47 | Log(const Log&); 48 | Log& operator = (const Log&); 49 | }; 50 | 51 | // template 52 | // LogImpl& operator <<(LogImpl& log, T const& value) { 53 | // log.your_stringstream << value; 54 | // return log; 55 | // } 56 | 57 | } 58 | 59 | logger::LogImpl& operator<< (logger::LogImpl&, bool); 60 | logger::LogImpl& operator<< (logger::LogImpl&, short); 61 | logger::LogImpl& operator<< (logger::LogImpl&, int); 62 | logger::LogImpl& operator<< (logger::LogImpl&, long); 63 | logger::LogImpl& operator<< (logger::LogImpl&, unsigned long long); 64 | logger::LogImpl& operator<< (logger::LogImpl&, unsigned short); 65 | logger::LogImpl& operator<< (logger::LogImpl&, unsigned int); 66 | logger::LogImpl& operator<< (logger::LogImpl&, unsigned long); 67 | logger::LogImpl& operator<< (logger::LogImpl&, float); 68 | logger::LogImpl& operator<< (logger::LogImpl&, double); 69 | logger::LogImpl& operator<< (logger::LogImpl&, char*); 70 | logger::LogImpl& operator<< (logger::LogImpl&, const char*); 71 | logger::LogImpl& operator<< (logger::LogImpl&, std::string); 72 | -------------------------------------------------------------------------------- /include/gl-utils/draw/parameters.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "blend.hpp" 4 | #include "depth.hpp" 5 | #include "stencil.hpp" 6 | 7 | namespace glUtils { 8 | 9 | struct CullingMode { 10 | static const GLenum None = GL_NONE; // show all 11 | static const GLenum CullFront = GL_FRONT; // CCW, hides front-facing faces 12 | static const GLenum CullBack = GL_BACK; // CW, hides back-facing faces 13 | }; 14 | typedef GLenum CullingMode_; 15 | 16 | struct PolygonMode { 17 | static const GLenum Point = GL_POINT; 18 | static const GLenum Line = GL_LINE; 19 | static const GLenum Fill = GL_FILL; 20 | }; 21 | typedef GLenum PolygonMode_; 22 | 23 | // enum class Smooth { 24 | // Fastest = GL_FASTEST, 25 | // Nicest = GL_NICEST, 26 | // DontCare = GL_DONT_CARE, 27 | // } 28 | 29 | /** 30 | * https://github.com/glium/glium/blob/master/src/draw_parameters/mod.rs#L246 31 | */ 32 | struct DrawParameters { 33 | Depth depth; 34 | Stencil stencil; 35 | Blend blend; 36 | f32 line_width = 1.0f; 37 | f32 point_size = 1.0f; 38 | PolygonMode_ polygon_mode = PolygonMode::Fill; 39 | bool dithering = false; // smoothen transition between colors 40 | CullingMode_ culling = CullingMode::CullBack; 41 | 42 | // It also affects glClear! 43 | bool color_write[4] = {true, true, true, true}; 44 | 45 | // Unimplemented: 46 | // Smooth smooth; // Requires blending to be on 47 | // bool multisampling = false; // better do at window creation 48 | // ? polygon_offset; // glPolygonOffset 49 | // SampleCoverage coverage; // glSampleCoverage 50 | // params.draw_primitives = true; 51 | // params.samples_passed_query = None; 52 | // params.time_elapsed_query = None; 53 | // params.primitives_generated_query = None; 54 | // params.transform_feedback_primitives_written_query = None; 55 | // params.condition = None; 56 | // params.transform_feedback = None; 57 | // params.provoking_vertex = ProvokingVertex::LastVertex; 58 | // params.primitive_bounding_box = (-1.0 .. 1.0, -1.0 .. 1.0, -1.0 .. 1.0, -1.0 .. 1.0); 59 | // params.primitive_restart_index = false; 60 | 61 | DrawParameters(){} 62 | }; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/sim/_SimBuffers.comp.glsl: -------------------------------------------------------------------------------- 1 | // START _SimBuffers.glsl 2 | 3 | // struct Transforms { 4 | // /*row_major*/ mat4 tfm; 5 | // vec4 quat; 6 | // }; 7 | 8 | // struct BoneSkinningData { 9 | // vec4 boneIndex; // x, y, z and w component are four bone indices per strand 10 | // vec4 boneWeight; // x, y, z and w component are four bone weights per strand 11 | // }; 12 | 13 | // 14 | // UAVs (read-write resources) 15 | // 16 | 17 | // RWStructuredBuffer g_HairVertexPositions; 18 | STRUCTURED_BUFFER(0, vec4, g_HairVertexPositions) 19 | // RWStructuredBuffer g_HairVertexPositionsPrev; 20 | STRUCTURED_BUFFER(1, vec4, g_HairVertexPositionsPrev) 21 | // RWStructuredBuffer g_HairVertexPositionsPrevPrev; 22 | STRUCTURED_BUFFER(2, vec4, g_HairVertexPositionsPrevPrev) 23 | // RWStructuredBuffer g_HairVertexTangents; 24 | STRUCTURED_BUFFER(3, vec4, g_HairVertexTangents) 25 | 26 | // #if USE_MESH_BASED_HAIR_TRANSFORM == 1 27 | // RWStructuredBuffer g_Transforms; 28 | // #endif 29 | 30 | 31 | // 32 | // SRVs (read resources) 33 | // 34 | 35 | // StructuredBuffer g_InitialHairPositions; 36 | STRUCTURED_BUFFER(4, vec4, g_InitialHairPositions) 37 | 38 | // probably strand's vertex rotation, but in global space 39 | // StructuredBuffer g_GlobalRotations; 40 | STRUCTURED_BUFFER(5, vec4, g_GlobalRotations) 41 | 42 | // lengths between vertices in strand 43 | // StructuredBuffer g_HairRestLengthSRV; 44 | STRUCTURED_BUFFER(6, float, g_HairRestLengthSRV) 45 | 46 | // used in local shape constraints, vector (vertex) -> (next_vertex) 47 | // StructuredBuffer g_HairRefVecsInLocalFrame; 48 | STRUCTURED_BUFFER(7, vec4, g_HairRefVecsInLocalFrame) 49 | 50 | // each follow hair is from guide/master root 51 | // StructuredBuffer g_FollowHairRootOffset; 52 | STRUCTURED_BUFFER(8, vec4, g_FollowHairRootOffset) 53 | 54 | // StructuredBuffer g_MeshVertices; 55 | // STRUCTURED_BUFFER(9, vec4, g_MeshVertices) 56 | 57 | // StructuredBuffer g_TransformedVerts; 58 | // STRUCTURED_BUFFER(10, vec4, g_TransformedVerts) 59 | 60 | // StructuredBuffer g_BoneSkinningData; 61 | // STRUCTURED_BUFFER(11, BoneSkinningData, g_BoneSkinningData) 62 | 63 | // END _SimBuffers.glsl 64 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/ppll_build.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | #pragma include "_utils.glsl" 4 | #pragma include "lib/TressFXPPLL.glsl" 5 | #pragma include "lib/TressFXPPLL.build.glsl" 6 | #pragma include "lib/TressFXRendering.coverage.glsl" 7 | 8 | // START ppll_build.frag 9 | // (main) 10 | 11 | // TODO Crassin's page allocator? 12 | 13 | uniform vec2 g_WinSize; 14 | 15 | in vec4 ps_Position; 16 | in vec4 ps_Tangent; 17 | in vec4 ps_p0p1; 18 | in vec4 ps_strandColor; 19 | // out vec4 out_color; 20 | 21 | // NOTE: very important 22 | // Remember we are not writing fragment color, but for all fragments we write 23 | // to SSBO / image2d. Normally, depth stencil can be done whatever (exp. when 24 | // fragment's depth is modified in pixel shader). But in our case, if depth/stencil 25 | // is done too late, we already written to SSBO etc. so yeah, do early 26 | // depth/stencil here 27 | layout(early_fragment_tests) in; // [earlydepthstencil] 28 | 29 | 30 | float get_alpha () { 31 | float coverage = ComputeCoverage(ps_p0p1.xy, ps_p0p1.zw, gl_FragCoord.xy, g_WinSize); 32 | return coverage * ps_strandColor.a; 33 | } 34 | 35 | void main () { 36 | float alpha = get_alpha(); // 1.0; 37 | if (alpha < 1.0 / 255.0) { 38 | discard; 39 | } 40 | 41 | // Allocate a new fragment in heads texture 42 | ivec2 vScreenAddress = ivec2(gl_FragCoord.xy); 43 | uint nNewFragmentAddress = AllocateFragment(vScreenAddress); 44 | 45 | if (nNewFragmentAddress != FRAGMENT_LIST_NULL) { 46 | uint nOldFragmentAddress = MakeFragmentLink(vScreenAddress, nNewFragmentAddress); 47 | WriteFragmentAttributes( 48 | nNewFragmentAddress, 49 | nOldFragmentAddress, 50 | vec4(ps_Tangent.xyz * 0.5 + vec3(0.5, 0.5, 0.5), alpha), // data 51 | ps_strandColor.xyz, // color 52 | ps_Position.z // depth 53 | ); 54 | } 55 | 56 | // out_color = vec4(0.16, 0.45, 0.64, 1.0); 57 | } 58 | 59 | // paging algo breakdown(very rough draft): 60 | // 1) pointer = curr_head[x,y] 61 | // 2) for i in [:PAGE] // or we can store in pointer current page offset 62 | // if linked_list[pointer+i] is unused: (should this be atomic?) 63 | // write here; break; 64 | // else: 65 | // addres = atomic_inc * 4 66 | // do the swap in head_texture 67 | // write to linked_list, update old pointer 68 | // 69 | -------------------------------------------------------------------------------- /src/gl-tfx/TFxSettings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "include_TFx_pls_no_warnings.hpp" 4 | #include "../../libs/amd_tressfx/include/TressFXSettings.h" 5 | 6 | 7 | namespace glTFx { 8 | 9 | struct TFxRenderingMode { 10 | static const i32 Normal = 0; 11 | static const i32 BinaryPPLL = 1; // fill single color 12 | static const i32 PPLLOverlap = 2; // blue - 1 overlap, red - 3 overlaps etc. 13 | }; 14 | 15 | struct TFxSettings { 16 | 17 | TFxSettings(){ 18 | this->model_matrix = glm::mat4(1); 19 | } 20 | 21 | // 22 | // model 23 | const char* object_name = "mohawk"; 24 | const char* filepath = "assets\\Ratboy\\Ratboy_mohawk.tfx"; 25 | i32 follow_hairs_per_guide_hair = 2; 26 | glm::mat4 model_matrix; 27 | 28 | 29 | // 30 | // rendering 31 | i32 render_mode = TFxRenderingMode::Normal; 32 | const bool use_shortcut = false; 33 | // color 34 | glm::vec4 root_color = {0.93, 0.11, 0.11, 1.0}; 35 | glm::vec4 tip_color = {0.09, 0.09, 0.14, 1.0}; 36 | float mid_alpha = 1.0; 37 | bool use_separate_tip_color = true; 38 | float strand_hue_rand_scale = 0.0; 39 | // thickness 40 | f32 hair_thickness = 0.1; 41 | f32 hair_thickness_at_tip_ratio = 0.5; // thick hair root, thin tip 42 | bool use_thin_tip = true; 43 | 44 | 45 | // 46 | // simulation 47 | TressFXSimulationSettings simulation_settings; 48 | float gravity_multipler = 1.0f; // depends on scale of the model 49 | bool show_wind = false; 50 | glm::vec4 wind0 = {0,0,0, 0}; // x,y,z, magnitude 51 | glm::vec4 wind1 = {0,0,0, 0}; // x,y,z, magnitude 52 | 53 | // g_FollowHairRootOffset_ is generated by TressFx lib, but it 54 | // completly disregards scale. Which means that we sometimes 55 | // end up with follow hairs all around the place. 56 | // Since these are just vector offsets from guide strand, 57 | // we can manipulate them easily 58 | float follow_hair_root_offset_multiplier = 1.0; 59 | 60 | // [x,y,z, radius] 61 | glm::vec4 collision_capsule0 = glm::vec4(0,0,0,0); 62 | glm::vec4 collision_capsule1 = glm::vec4(0,0,0,0); 63 | glm::vec4 collision_capsule2 = glm::vec4(0,0,0,0); 64 | glm::vec4 collision_capsule3 = glm::vec4(0,0,0,0); 65 | }; 66 | 67 | } // namespace glTFx 68 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/TressFXSimulation.h: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Invokes simulation compute shaders. 3 | // ---------------------------------------------------------------------------- 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | #ifndef TRESSFXSIMULATION_H_ 27 | #define TRESSFXSIMULATION_H_ 28 | 29 | // AMD 30 | #include "AMD_Types.h" 31 | #include "TressFXCommon.h" 32 | 33 | // TressFX 34 | #include "TressFXGPUInterface.h" 35 | 36 | class TressFXHairObject; 37 | 38 | class TressFXSimulation : private TressFXNonCopyable 39 | { 40 | public: 41 | void Initialize(EI_Device* pDevice, EI_LayoutManagerRef simLayoutManager); 42 | void Shutdown(EI_Device* pDevice); 43 | 44 | void Simulate(EI_CommandContextRef commandContext, TressFXHairObject& hairObject); 45 | 46 | private: 47 | // Maybe these just need to be compute shader references. 48 | EI_PSO* mVelocityShockPropagationPSO; 49 | EI_PSO* mIntegrationAndGlobalShapeConstraintsPSO; 50 | EI_PSO* mLocalShapeConstraintsPSO; 51 | EI_PSO* mLengthConstriantsWindAndCollisionPSO; 52 | EI_PSO* mUpdateFollowHairVerticesPSO; 53 | }; 54 | 55 | #endif // TRESSFXSIMULATION_H_ 56 | -------------------------------------------------------------------------------- /bin/generate_makefile.clang.bat: -------------------------------------------------------------------------------- 1 | @SETLOCAL 2 | 3 | @set COMPILE_FLAGS=-target x86_64-w64-mingw -stdlib=libstdc++ 4 | @set COMPILE_FLAGS= %COMPILE_FLAGS% -isystem \"C:\programs\install\MinGW64\x86_64\lib\gcc\x86_64-w64-mingw32\7.1.0\include\c++\x86_64-w64-mingw32\" 5 | @set COMPILE_FLAGS= %COMPILE_FLAGS% -isystem \"C:\programs\install\MinGW64\x86_64\lib\gcc\x86_64-w64-mingw32\7.1.0\include\c++\" 6 | @set COMPILE_FLAGS= %COMPILE_FLAGS% -isystem \"C:\programs\install\LLVM\lib\clang\4.0.1\include\" 7 | @set COMPILE_FLAGS= %COMPILE_FLAGS% -isystem \"C:\programs\install\MinGW64\x86_64\x86_64-w64-mingw32\include\" 8 | @set COMPILE_FLAGS= %COMPILE_FLAGS% -fansi-escape-codes -fcolor-diagnostics 9 | 10 | @rem -DSDL2_ROOT_DIR="C:/programs/libraries/SDL2-2.0.4/x86_64-w64-mingw32" ^ 11 | @rem -DGLM_ROOT_DIR="C:/programs/libraries/glm-0.9.7.5" ^ 12 | 13 | C:\programs\portable\cmake-3.6.1-win64-x64\bin\cmake .^ 14 | -G "MSYS Makefiles" ^ 15 | -DCMAKE_CXX_COMPILER="Clang" ^ 16 | -DCMAKE_RC_COMPILER="c:/programs/install/MinGW64/x86_64/bin/windres.exe" ^ 17 | -DM_ADDITIONAL_LIBS="stdc++" ^ 18 | -DCMAKE_CXX_FLAGS="%COMPILE_FLAGS%" ^ 19 | -DCMAKE_BUILD_TYPE="Debug" ^ 20 | -DGLM_ROOT_DIR="C:/programs/libraries/glm-0.9.9.0" ^ 21 | -DSDL2_ROOT_DIR="C:/programs/libraries/SDL2-2.0.8/x86_64-w64-mingw32" ^ 22 | -DGLAD_ROOT_DIR="C:/programs/libraries/GLAD" 23 | 24 | @rem OLD FLAG: 25 | @rem -DCMAKE_CXX_FLAGS="-target x86_64-w64-mingw -isystem \"C:\programs\install\MinGW64\x86_64\include\" -isystem \"C:\programs\install\MinGW64\x86_64\x86_64-w64-mingw32\include\" -isystem \"C:\programs\install\MinGW64\x86_64\x86_64-w64-mingw32\include\c++\" -isystem \"C:\programs\install\MinGW64\x86_64\x86_64-w64-mingw32\include\c++\x86_64-w64-mingw32\"" ^ 26 | 27 | @rem -target x86_64-w64-mingw 28 | @rem -isystem \"C:\programs\install\MinGW64\x86_64\include\" 29 | @rem -isystem \"C:\programs\install\MinGW64\x86_64\x86_64-w64-mingw32\include\" 30 | @rem -isystem \"C:\programs\install\MinGW64\x86_64\x86_64-w64-mingw32\include\c++\" 31 | @rem -isystem \"C:\programs\install\MinGW64\x86_64\x86_64-w64-mingw32\include\c++\x86_64-w64-mingw32\" 32 | 33 | 34 | @rem MISC 35 | @rem -DCMAKE_CXX_FLAGS="-i686-w64-mingw32" ^ 36 | @rem -DSDL2_ROOT_DIR="C:/programs/libraries/SDL2-2.0.4/x86_64-w64-mingw32" ^ 37 | @rem -DCMAKE_RC_COMPILER="c:/programs/install/MinGW64/bin/windres.exe" ^ 38 | @rem -DCMAKE_CXX_COMPILER="Clang" ^ 39 | @rem -DCMAKE_BUILD_TYPE="Debug" ^ 40 | -------------------------------------------------------------------------------- /include/gl-utils/VAO.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace glUtils { 4 | 5 | struct VertexAttributeType { 6 | // GL_INT, GL_FLOAT, etc. 7 | // only simple types, do not use FLOAT_VEC2 etc. 8 | GLenum base_type = GL_FLOAT; 9 | // one of: {1,2,3,4} 10 | u32 components = 1; 11 | }; 12 | 13 | struct VertexAttribute { 14 | 15 | VertexAttribute(const RawBuffer*, VertexAttributeType, u32 offset, u32 stride); 16 | 17 | VertexAttributeType type; 18 | 19 | // NOTE: if attribute is a matrix, this value refers to 1st column. 20 | // Additional 3 attributes (for mat4) will be reserved for other columns 21 | // NOTE: You may want to use 'in layout(location=X) T v' inside shader 22 | // 23 | // @see glBindAttribLocation(program.gl_id, location_to_set, "position") 24 | // @see glGetAttribLocation(program.gl_id, "position"); 25 | // @see https://www.youtube.com/watch?v=mL6BvXVtd9Y 26 | // @see https://stackoverflow.com/questions/4635913/explicit-vs-automatic-attribute-location-binding-for-opengl-shaders 27 | u32 gl_location = 0; 28 | 29 | const RawBuffer* buffer = nullptr; 30 | 31 | // From the beginning of the buffer, how much bytes till 1st 32 | // occurence of this attribute data. Mainly 2 use cases: 33 | // - when [{pos1,uv1}, {pos2,uv2}, ..] 34 | // then offset for pos is 0 and for uv is sizeof(pos) 35 | // - when [pos1,pos2,...,posN, uv1,uv2,...,uvN] 36 | // then offset for pos is 0 and for uv is N*sizeof(pos) 37 | u32 offset = 0; 38 | 39 | // Bytes between next occurance of this attribute e.g. 40 | // - when [{pos1,uv1}, {pos2,uv2}, ..] 41 | // then stride for both pos and uv is (sizeof(pos) + sizeof(uv)), 42 | // as this is how much bytes is between each next vertex data 43 | // - when [pos1,pos2,...,posN, uv1,uv2,...,uvN] 44 | // then stride for pos is sizeof(pos) and for uv is sizeof(uv) 45 | u32 stride = 0; 46 | }; 47 | 48 | struct VAO { 49 | // typedef gfx::Vector VertextAttrList; 50 | 51 | // VAO(GfxAllocator& alloc) : attributes(alloc){} 52 | 53 | // inline bool is_created () const noexcept { return gl_id != VAO_UNITIALIZED; } 54 | 55 | GLuint gl_id = GL_UTILS_NOT_CREATED_ID; 56 | // VertextAttrList attributes; 57 | 58 | inline bool is_created () const noexcept { return gl_id != GL_UTILS_NOT_CREATED_ID; } 59 | }; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/gl-utils/texture/apply_texture_options.impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static void setTexParam(const glUtils::Texture&, GLenum pname, i32); 4 | static void setTexParam(const glUtils::Texture&, GLenum pname, u32*); 5 | 6 | namespace glUtils { 7 | 8 | void apply_texture_options(const Texture& texture, const TextureOpts& opts) { 9 | // if (version >= ::utils::Version(4, 3)) { 10 | // not working? 11 | // setTexParam(texture, GL_DEPTH_STENCIL_TEXTURE_MODE, opts.read_depth_if_depth_stencil ? GL_DEPTH_COMPONENT : GL_STENCIL_COMPONENT); 12 | // } 13 | 14 | setTexParam(texture, GL_TEXTURE_BASE_LEVEL, (i32)opts.mipmap_min); 15 | setTexParam(texture, GL_TEXTURE_MAX_LEVEL, (i32)opts.mipmap_max); 16 | setTexParam(texture, GL_TEXTURE_BORDER_COLOR, (u32*)opts.border_color); 17 | setTexParam(texture, GL_TEXTURE_MIN_FILTER, opts.filter_min); 18 | setTexParam(texture, GL_TEXTURE_MAG_FILTER, opts.filter_mag); 19 | setTexParam(texture, GL_TEXTURE_MIN_LOD, opts.lod_min); 20 | setTexParam(texture, GL_TEXTURE_MAX_LOD, opts.lod_max); 21 | 22 | setTexParam(texture, GL_TEXTURE_SWIZZLE_R, opts.swizzle[0]); 23 | setTexParam(texture, GL_TEXTURE_SWIZZLE_G, opts.swizzle[1]); 24 | setTexParam(texture, GL_TEXTURE_SWIZZLE_B, opts.swizzle[2]); 25 | setTexParam(texture, GL_TEXTURE_SWIZZLE_A, opts.swizzle[3]); 26 | setTexParam(texture, GL_TEXTURE_WRAP_S, opts.wrap[0]); 27 | setTexParam(texture, GL_TEXTURE_WRAP_T, opts.wrap[1]); 28 | setTexParam(texture, GL_TEXTURE_WRAP_R, opts.wrap[2]); 29 | 30 | // GL_TEXTURE_LOD_BIAS, must be < GL_MAX_TEXTURE_LOD_BIAS 31 | setTexParam(texture, GL_TEXTURE_LOD_BIAS, opts.lod_bias); 32 | 33 | // Just when You thought the OpenGL docs could not get any worse.. 34 | /*if (opts.depth_compare_fn == TextureCompareFn::None) { 35 | setTexParam(texture, GL_TEXTURE_COMPARE_MODE, GL_NONE); 36 | } else { 37 | setTexParam(texture, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); 38 | setTexParam(texture, GL_TEXTURE_COMPARE_FUNC, opts.depth_compare_fn); 39 | }*/ 40 | } 41 | 42 | } // namespace glUtils 43 | 44 | void setTexParam(const glUtils::Texture& texture, GLenum pname, i32 value) { 45 | GFX_GL_CALL(glTextureParameteri, texture.gl_id, pname, value); 46 | } 47 | 48 | void setTexParam(const glUtils::Texture& texture, GLenum pname, u32* data) { 49 | GFX_GL_CALL(glTextureParameterIuiv, texture.gl_id, pname, data); 50 | } 51 | -------------------------------------------------------------------------------- /src/gl-utils/buffer/write.impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static u32 calculate_write_range(const glUtils::RawBuffer& buf, const glUtils::BufferRange range_bytes_, const void*const data) { 4 | GFX_FAIL_IF(!buf.is_created(), "Tried to write ", range_bytes_.size(), " bytes into deleted buffer"); 5 | GFX_FAIL_IF(data == nullptr, "Tried to write data from nullptr. You probably wanted to write some existing data"); 6 | 7 | i32 size_left = buf.bytes - range_bytes_.offset(), 8 | bytes_to_write = std::min(size_left, (i32) range_bytes_.size()); 9 | 10 | GFX_FAIL_IF(size_left < 1, "Tried to write at offset ", range_bytes_.offset(), ", but buffer has only ", buf.bytes, " bytes"); 11 | GFX_FAIL_IF(bytes_to_write < 1, "Tried to write ", bytes_to_write, " bytes. You probably wanted to write >0 bytes"); 12 | 13 | return bytes_to_write; 14 | } 15 | 16 | namespace glUtils { 17 | 18 | u32 write (const RawBuffer& buf, const BufferRange range_bytes_, const void*const data) { 19 | BufferRange range_bytes = { 20 | range_bytes_.offset(), 21 | calculate_write_range(buf, range_bytes_, data) 22 | }; 23 | if (range_bytes.size() == 0) { 24 | return 0; 25 | } 26 | 27 | if (buf.is_persistent_mapping()) { 28 | // NOTE: immpossible to realocate buffer this way 29 | // Mapping guard = this->map(range_el, false, true); 30 | // memcpy(guard, data, range_bytes.size()); 31 | GFX_FAIL("Writing to persistently mapped buffers is not supported ATM"); 32 | } else if (buf.is_immutable()) { 33 | // we are immutable -> create new buffer and copy into ourself 34 | // GpuBuffer buf; 35 | // buf.init(ctxt.last_error, *ctxt, BufferBindType::CopyReadBuffer, format, BufferUsagePattern::Dynamic) 36 | // .allocate(ctxt.last_error, range_el.size) 37 | // .write(ctxt.last_error, range_el, data) // we can write to newly created buffer 38 | // .copy_to(ctxt.last_error, *this, {range_el.size}, range_el.offset) 39 | // .release(ctxt.last_error); 40 | // if (!es2.is_ok()) { es.reset(); es << es2.msg(); return *this; } 41 | GFX_FAIL("Writing to immutable buffer is not supported ATM"); 42 | } else { 43 | // normal case, inlcuding when allocating new buffer of any type 44 | // if (ctxt.version() > Version(4,3)) { 45 | // glInvalidateBufferData(buf.gl_id); // give hint is not needed 46 | // } 47 | 48 | GFX_GL_CALL(glNamedBufferSubData, buf.gl_id, range_bytes.offset(), range_bytes.size(), data); 49 | } 50 | 51 | return range_bytes.size(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/sim/_SimCommon.comp.glsl: -------------------------------------------------------------------------------- 1 | // START _SimCommon.glsl 2 | 3 | // HLSL -> GLSL notes 4 | // (from: https://anteru.net/blog/2016/mapping-between-hlsl-and-glsl/index.html) 5 | // * SV_DispatchThreadID gl_GlobalInvocationID 6 | // * SV_GroupID gl_WorkGroupID 7 | // * SV_GroupIndex gl_LocalInvocationIndex 8 | 9 | 10 | // If you change the value below, you must change it in TressFXAsset.h as well. 11 | #define THREAD_GROUP_SIZE 64 12 | 13 | // ?Old skinning method? 14 | #define USE_MESH_BASED_HAIR_TRANSFORM 0 15 | 16 | // Toggle capsule collisions 17 | #ifndef TRESSFX_COLLISION_CAPSULES 18 | #define TRESSFX_COLLISION_CAPSULES 0 19 | #endif 20 | 21 | struct PerVertexData { 22 | uint localId; // [0-64] unique indexForSharedMem 23 | uint strandId; // {0,1}, localStrandIndex (each workgroup operates on 2 strands) 24 | uint strandId_global; // globalStrandIndex 25 | uint vertexId; // [0-32], localVertexIndex 26 | uint vertexId_global; // globalVertexIndex 27 | uint strandType; // const 0 28 | }; 29 | 30 | PerVertexData GetPerVertexData(uint local_id, uint group_id, inout uint numVerticesInTheStrand) { 31 | numVerticesInTheStrand = (THREAD_GROUP_SIZE / g_NumOfStrandsPerThreadGroup); 32 | 33 | PerVertexData d; 34 | d.localId = local_id; 35 | d.strandId = local_id % g_NumOfStrandsPerThreadGroup; 36 | d.strandId_global = group_id * g_NumOfStrandsPerThreadGroup + d.strandId; 37 | d.strandId_global *= (g_NumFollowHairsPerGuideHair+1); 38 | d.vertexId = (local_id - d.strandId) / g_NumOfStrandsPerThreadGroup; 39 | d.vertexId_global = d.strandId_global * numVerticesInTheStrand + d.vertexId; 40 | d.strandType = GetStrandType(d.strandId_global); 41 | return d; 42 | } 43 | 44 | bool IsMovable(vec4 particle) { 45 | if ( particle.w > 0 ){ return true;} 46 | return false; 47 | } 48 | 49 | void CalcIndicesInStrandLevelMaster( 50 | uint local_id, uint group_id, 51 | inout uint globalStrandIndex, inout uint numVerticesInTheStrand, 52 | inout uint globalRootVertexIndex, 53 | inout uint strandType) 54 | { 55 | globalStrandIndex = THREAD_GROUP_SIZE*group_id + local_id; 56 | globalStrandIndex *= (g_NumFollowHairsPerGuideHair+1); 57 | numVerticesInTheStrand = (THREAD_GROUP_SIZE / g_NumOfStrandsPerThreadGroup); 58 | strandType = GetStrandType(globalStrandIndex); 59 | globalRootVertexIndex = globalStrandIndex * numVerticesInTheStrand; 60 | } 61 | 62 | void GroupMemoryBarrierWithGroupSync () { 63 | memoryBarrierShared(); 64 | barrier(); 65 | } 66 | 67 | // END _SimCommon.glsl 68 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/TressFXSDFInputMeshInterface.h: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Signed distance fields are generated from triangle meshes. 3 | // This is the interface to a triangle mesh for use by TressFXSDFCollision 4 | // to generate the SDF. 5 | // ---------------------------------------------------------------------------- 6 | // 7 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | // 27 | 28 | #pragma once 29 | 30 | #include "Math/Vector3D.h" 31 | #include "TressFXGPUInterface.h" 32 | 33 | class TressFXSDFInputMeshInterface 34 | { 35 | public: 36 | virtual ~TressFXSDFInputMeshInterface() {} 37 | 38 | // Returns the GPU buffer containing the mesh data. It will be an input to SDF generator. 39 | virtual EI_StructuredBuffer& GetMeshBuffer() = 0; 40 | 41 | // Return the GPU index buffer of the mesh. 42 | virtual EI_StructuredBuffer& GetTrimeshVertexIndicesBuffer() = 0; 43 | 44 | // Returns the number of vertices of the mesh 45 | virtual int GetNumMeshVertices() = 0; 46 | 47 | // Returns the number of triangles of the mesh 48 | virtual int GetNumMeshTriangle() = 0; 49 | 50 | // Returns the byte size of mesh buffer data element. 51 | virtual size_t GetSizeOfMeshElement() = 0; 52 | 53 | // Returns the bounding box of the current mesh. 54 | virtual void GetBoundingBox(AMD::tressfx_vec3& min, AMD::tressfx_vec3& max) = 0; 55 | }; -------------------------------------------------------------------------------- /libs/amd_tressfx/include/Math/Transform.h: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // File: Transform.h 3 | // 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | //-------------------------------------------------------------------------------------- 26 | 27 | #pragma once 28 | 29 | #include "Quaternion.h" 30 | #include "Vector3D.h" 31 | 32 | namespace AMD 33 | { 34 | class tressfx_transform 35 | { 36 | public: 37 | tressfx_transform(void); 38 | tressfx_transform(const tressfx_transform& other); 39 | tressfx_transform(const tressfx_vec3& translation, const tressfx_quat& rotation); 40 | ~tressfx_transform(void); 41 | 42 | private: 43 | tressfx_vec3 m_Translation; 44 | tressfx_quat m_Rotation; 45 | 46 | public: 47 | const tressfx_vec3& GetTranslation() const { return m_Translation; } 48 | const tressfx_quat& GetRotation() const { return m_Rotation; } 49 | tressfx_vec3& GetTranslation() { return m_Translation; } 50 | tressfx_quat& GetRotation() { return m_Rotation; } 51 | void Inverse(); 52 | tressfx_transform InverseOther() const; 53 | 54 | tressfx_vec3 operator*(const tressfx_vec3& vector) const; 55 | tressfx_transform operator*(const tressfx_transform& transform) const; 56 | tressfx_transform& operator=(const tressfx_transform& other); 57 | }; 58 | 59 | } // namespace AMD 60 | -------------------------------------------------------------------------------- /src/gl-utils/buffer/malloc.impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static void allocate_buffer (glUtils::RawBuffer& buf); 4 | 5 | namespace glUtils { 6 | 7 | RawBuffer malloc(u32 bytes, BufferUsagePattern usage_pattern) { 8 | RawBuffer buffer; 9 | 10 | GFX_FAIL_IF(bytes == 0, "Could not allocate buffer of size 0. Use clear() instead."); 11 | 12 | GFX_GL_CALL(glCreateBuffers, 1, &buffer.gl_id); 13 | buffer.bytes = bytes; 14 | buffer.usage_pattern = usage_pattern; 15 | 16 | allocate_buffer(buffer); 17 | 18 | return buffer; 19 | } 20 | 21 | } 22 | 23 | void allocate_buffer (glUtils::RawBuffer& buf) { 24 | using namespace glUtils; 25 | 26 | GLuint //mutable_storage_flags, // flags for glBufferData 27 | immutable_storage_flags; // flags for glBufferStorage 28 | bool immutable = false; 29 | 30 | switch (buf.usage_pattern) { 31 | case BufferUsagePattern::Persistent: 32 | // mutable_storage_flags = GL_DYNAMIC_DRAW; 33 | immutable_storage_flags = GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 34 | immutable = true; 35 | break; 36 | case BufferUsagePattern::Dynamic: 37 | // mutable_storage_flags = GL_DYNAMIC_DRAW; 38 | immutable_storage_flags = GL_DYNAMIC_STORAGE_BIT | GL_CLIENT_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 39 | break; 40 | case BufferUsagePattern::Default: 41 | // mutable_storage_flags = GL_STATIC_DRAW; 42 | immutable_storage_flags = GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 43 | break; 44 | case BufferUsagePattern::Immutable: 45 | // mutable_storage_flags = GL_STATIC_DRAW; 46 | immutable_storage_flags = 0; 47 | immutable = true; 48 | break; 49 | } 50 | 51 | GLint true_allocated_size = -1; 52 | 53 | GFX_GL_CALL(glNamedBufferStorage, buf.gl_id, buf.bytes, nullptr, immutable_storage_flags); 54 | GFX_GL_CALL(glGetNamedBufferParameteriv, buf.gl_id, GL_BUFFER_SIZE, &true_allocated_size); 55 | 56 | if (buf.bytes != (u32)true_allocated_size) { 57 | destroy(buf); 58 | GFX_FAIL("Could not allocate buffer - out of memory. Tried allocating ", 59 | buf.bytes, " bytes, only ", true_allocated_size, " were allocated"); 60 | return; 61 | } 62 | 63 | /* 64 | TODO create mapping during buffer init if persistent 65 | if (immutable && usage_pattern == BufferUsagePattern::Persistent) { 66 | GFX_GL_CALL(glMapNamedBufferRange, id, 0, size as GL_types::GLsizeiptr, 67 | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | 68 | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); 69 | 70 | if ptr.is_null() { 71 | let error = ::get_gl_error(ctxt); 72 | panic!("GFX_GL_CALL(glMapBufferRange returned null , error: {:?})", error); 73 | } 74 | } 75 | */ 76 | } 77 | -------------------------------------------------------------------------------- /src/camera_ortho.impl.hpp: -------------------------------------------------------------------------------- 1 | glm::vec3 Camera::get_position () const noexcept { 2 | glm::mat4 view(1); 3 | view = glm::rotate(view, this->angles[0], {1, 0, 0}); 4 | view = glm::rotate(view, this->angles[1], {0, 1, 0}); 5 | 6 | glm::vec4 translate = {0, 0, -this->camera_distance, 1}; 7 | auto res = view * translate; 8 | if (res.z > 0) { res.y = -res.y; } // ?! 9 | return glm::vec3(res.x, res.y, -res.z); 10 | } 11 | 12 | struct CameraOrthoInputState { 13 | bool is_clicked = false; 14 | i32 last_x = 0, last_y = 0; 15 | }; 16 | static CameraOrthoInputState camera_ois; 17 | 18 | static glm::mat4 get_view_matrix (const Camera& state) { 19 | glm::mat4 view(1); 20 | 21 | // Opengl matrices are 'applied' in reverse, read from last to first: 22 | // 3. move back 23 | view = glm::translate(view, {0, 0, -state.camera_distance}); 24 | // 2. rotate up-down 25 | view = glm::rotate(view, state.angles[0], {1, 0, 0}); 26 | // 1. rotate left-right 27 | view = glm::rotate(view, state.angles[1], {0, 1, 0}); 28 | 29 | return view; 30 | } 31 | 32 | static glm::mat4 get_proj_matrix (const GlobalState& state) { 33 | const auto& camera = state.camera; 34 | return glm::perspective( 35 | glm::radians(camera.fov_dgr), 36 | state.aspect_ratio(), 37 | camera.zNear, camera.zFar); 38 | } 39 | 40 | void update_camera (GlobalState& state, const SDL_Event& ev) { 41 | auto& camera = state.camera; 42 | 43 | if (ev.type == SDL_MOUSEBUTTONUP || ev.type == SDL_MOUSEBUTTONDOWN) { 44 | if (ev.button.button == SDL_BUTTON_LEFT) { 45 | camera_ois.is_clicked = ev.button.type == SDL_MOUSEBUTTONDOWN; 46 | camera_ois.last_x = ev.button.x; 47 | camera_ois.last_y = ev.button.y; 48 | } 49 | } else if (ev.type == SDL_MOUSEMOTION) { 50 | if (camera_ois.is_clicked) { 51 | auto dx = ev.motion.x - camera_ois.last_x; 52 | auto dy = ev.motion.y - camera_ois.last_y; 53 | camera_ois.last_x = ev.motion.x; 54 | camera_ois.last_y = ev.motion.y; 55 | 56 | camera.angles.y += dx * camera.camera_sensitivity; 57 | camera.angles.x += dy * camera.camera_sensitivity; 58 | while (camera.angles.y < 0) {camera.angles.y += glm::radians(360.);} 59 | while (camera.angles.y >= glm::radians(360.)) {camera.angles.y -= glm::radians(360.);} 60 | if (camera.angles.x < -glm::radians(89.)) {camera.angles.x = -glm::radians(89.);} 61 | if (camera.angles.x > glm::radians(89.)) {camera.angles.x = glm::radians(89.);} 62 | } 63 | } else if (ev.type == SDL_MOUSEWHEEL) { 64 | camera.camera_distance += -ev.wheel.y * camera.camera_distance_sensitivity; 65 | } 66 | 67 | state.camera.view = get_view_matrix(state.camera); 68 | state.camera.projection = get_proj_matrix(state); 69 | } 70 | -------------------------------------------------------------------------------- /include/gl-utils/texture/texture.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "TextureOpts.hpp" 4 | 5 | namespace glUtils { 6 | 7 | /** 8 | * 9 | * Unsized vs Sized and format vs internal format (in normalized environment) 10 | * 11 | * Internal format is how memory will be allocated on GPU. It is expressed in 'sized' GLenum e.g. GL_RGBA8 (4 channels of unsigned byte each). On the other hand, when writing/reading we usually provide 3 arguments (GLenum format, GLenum type, GLvoid * pixels), where 'format' is 'unsized' info about channels (e.g. GL_R, GL_RG, GL_RGB, GL_RGBA), 'type' is type in each channel (there are special values like GL_UNSIGNED_SHORT_5_5_5_1, that escape normal conventions, since hard to expect short to be 5bits) and 'pixels' is data. Unsized are used to describe data that we provide so it can be written (see TextureWriteSource) or texture format that we want to read (see TextureReadTarget). 12 | * NOTE: format := what we provided in data. It is unsized meaning e.g. GL_R, GL_RG, GL_RGB, GL_RGBA instead of GL_RGBA8 etc. 13 | * NOTE: internal format := how in GPU will be visisble/allocated. Lists all bits variations 14 | * 15 | * 16 | * 'level' parameter: in OpenGL docs always mean mipmap levels 17 | * - lvl0 - original, 18 | * - lvl1 - 1st mipmap (each dimension halfed) 19 | * - lvl2 - 2st mipmap (each dimension is quater of original) etc. 20 | * 21 | * 22 | * Normalized vs unnormalized 23 | * 24 | * Normalized means that all results will be converted to float in the range [0,1] ([-1,1] for signed formats). Unnormalized is left as is. See https://stackoverflow.com/questions/34497195/difference-between-format-and-internalformat#comment56736641_34497470 . Normally, normalized textures are used. In case raw ints should be used (unnormalized), please use GL_..._INTEGER (ex. GL_RGBA_INTEGER) variants of channels. 25 | * NOTE: unnormalized is also known as unclamped (name based on GLSL clamp function) 26 | * TODO add write_source.use_unnormalized_integers flag for unnormalized 27 | * 28 | */ 29 | struct Texture { 30 | GLuint gl_id = GL_UTILS_NOT_CREATED_ID; 31 | 32 | /** GL_TEXTURE_2D, GL_TEXTURE_3D etc. */ 33 | GLenum gl_type = GL_TEXTURE_2D; 34 | 35 | /** [0] - width, 36 | * [1] - height, 37 | * [2] - depth/array size 38 | */ 39 | u32 dimensions[3] = {0,0,0}; 40 | 41 | /** filtering etc. */ 42 | TextureOpts opts; 43 | 44 | /** GL_R8 / GL_RGBA8 / GL_RGBA32F etc. */ 45 | GLenum sized_pixel_format = GL_RGBA8; 46 | 47 | /** Number of mipmap levels (`0` means just the main texture) */ 48 | u32 mipmap_levels = 0; 49 | 50 | /** Not always used */ 51 | u32 multisample = 1; 52 | 53 | inline bool is_created () const noexcept { return gl_id != GL_UTILS_NOT_CREATED_ID; } 54 | }; 55 | 56 | } 57 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/TressFXCommon.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // Constant buffer layouts. 3 | //------------------------------------------------------------------------------------- 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | #ifndef TRESSFXCOMMON_H_ 27 | #define TRESSFXCOMMON_H_ 28 | 29 | #include "AMD_Types.h" 30 | 31 | #define TRESSFX_COLLISION_CAPSULES 0 32 | #define TRESSFX_MAX_NUM_COLLISION_CAPSULES 8 33 | 34 | #define TRESSFX_SIM_THREAD_GROUP_SIZE 64 35 | 36 | namespace AMD 37 | { 38 | namespace TRESSFX 39 | { 40 | #pragma warning(push) 41 | #pragma warning(disable : 4201) // disable warning C4201: nonstandard extension used : nameless struct/union 42 | AMD_DECLARE_BASIC_VECTOR_TYPE; 43 | #pragma warning(pop) 44 | } 45 | } 46 | 47 | 48 | #ifdef TRESSFX_NON_COPYABLE_MODERN_CPP 49 | 50 | class TressFXNonCopyable 51 | { 52 | public: 53 | TressFXNonCopyable() = default; 54 | ~TressFXNonCopyable() = default; 55 | 56 | protected: 57 | TressFXNonCopyable(const TressFXNonCopyable&) = delete; 58 | void operator=(const TressFXNonCopyable&) = delete; 59 | }; 60 | 61 | #else 62 | 63 | class TressFXNonCopyable 64 | { 65 | public: 66 | TressFXNonCopyable() {} 67 | ~TressFXNonCopyable() {} 68 | 69 | private: 70 | TressFXNonCopyable(const TressFXNonCopyable&){}; 71 | void operator=(const TressFXNonCopyable&){}; 72 | }; 73 | 74 | #endif 75 | 76 | /// Computes the minimum 77 | template 78 | inline Type TressFXMin(Type a, Type b) 79 | { 80 | return (a < b) ? a : b; 81 | } 82 | 83 | 84 | 85 | 86 | #endif // TRESSFXCOMMON_H_ 87 | -------------------------------------------------------------------------------- /src/logging/Logging.cpp: -------------------------------------------------------------------------------- 1 | #include "../../include/logging/Logger.hpp" 2 | #include 3 | #include 4 | 5 | namespace logger { 6 | 7 | // default logging level 8 | LogLevel Log::ReportingLevel = LogLevel::Debug; 9 | 10 | struct MsgMetaData; 11 | 12 | struct ColorFg { 13 | static const int Black = 30; 14 | static const int Red = 31; 15 | static const int Green = 32; 16 | static const int Yellow = 33; 17 | static const int Blue = 34; 18 | static const int Magenta= 35; 19 | static const int Cyan = 36; 20 | static const int White = 37; 21 | }; 22 | typedef int ColorFg_; 23 | 24 | class LogImpl { 25 | public: 26 | typedef const char* const LogPattern; 27 | static LogPattern Pattern; 28 | 29 | typedef std::ostringstream stream_t; 30 | 31 | void set_header(const MsgMetaData&); 32 | 33 | void flush () { 34 | auto str = this->os.str(); 35 | std::cout << str << std::endl; 36 | } 37 | 38 | public: 39 | stream_t os; 40 | }; 41 | 42 | Log::Log() : impl(new LogImpl){} // ugh! PIMPL 43 | 44 | Log::~Log(){ 45 | this->impl->flush(); 46 | delete this->impl; 47 | } 48 | 49 | } 50 | 51 | #include "formatter.impl.hpp" 52 | 53 | using namespace logger; 54 | 55 | LogImpl& operator<< (LogImpl& l, bool v) { 56 | const char* vals[] = {"True", "False"}; 57 | const char* val_str = vals[v ? 0 : 1]; 58 | l.os << (val_str); 59 | return l; 60 | } 61 | // signed 62 | LogImpl& operator<< (LogImpl& l, short val){ return l << (long) val; } 63 | LogImpl& operator<< (LogImpl& l, int val) { return l << (long) val; } 64 | LogImpl& operator<< (LogImpl& l, long val) { 65 | char buffer [128]; 66 | snprintf(buffer, sizeof(buffer), "%ld", val); 67 | l.os << buffer; 68 | return l; 69 | } 70 | // unsigned 71 | LogImpl& operator<< (LogImpl& l, unsigned short val){ return l << (unsigned long) val; } 72 | LogImpl& operator<< (LogImpl& l, unsigned int val) { return l << (unsigned long) val; } 73 | LogImpl& operator<< (LogImpl& l, unsigned long long val) { return l << (unsigned long) val; } // bwahahahahahahhahaaha! 74 | LogImpl& operator<< (LogImpl& l, unsigned long val) { 75 | char buffer [128]; 76 | snprintf(buffer, sizeof(buffer), "%lu", val); 77 | l.os << buffer; 78 | return l; 79 | } 80 | // floats 81 | LogImpl& operator<< (LogImpl& l, float val) { return l << (double) val; } 82 | LogImpl& operator<< (LogImpl& l, double val) { 83 | char buffer [128]; 84 | snprintf(buffer, sizeof(buffer), "%f", val); 85 | l.os << buffer; 86 | return l; 87 | } 88 | // strings 89 | LogImpl& operator<< (LogImpl& l, char* val) { return l << std::string(val); } 90 | LogImpl& operator<< (LogImpl& l, const char* val) { return l << std::string(val); } 91 | LogImpl& operator<< (LogImpl& l, std::string str) { 92 | // TODO handle '\0' 93 | l.os << str; 94 | return l; 95 | } 96 | -------------------------------------------------------------------------------- /src/gl-tfx/TFxSample.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // #include "SuTypes.h" 4 | // #include "SushiGPUInterface.h" 5 | // #include "EngineTressFXObject.h" 6 | // #include "SuAnimatedModel.h" 7 | // #include "SuCommandQueue.h" 8 | // #include "SuEffect.h" 9 | // #include "SuEffectReloadListener.h" 10 | // #include "SuGPUResource.h" 11 | 12 | #include "include_TFx_pls_no_warnings.hpp" 13 | #include "../../libs/amd_tressfx/include/TressFXAsset.h" 14 | #include "../../libs/amd_tressfx/include/TressFXGPUInterface.h" 15 | #include "../../libs/amd_tressfx/include/TressFXSettings.h" 16 | 17 | #include 18 | 19 | // lib forwards 20 | // - 21 | 22 | struct GlobalState; // global state from GUI 23 | 24 | namespace glTFx { 25 | 26 | class TFxPPLL; 27 | class TFxShortCut; 28 | class TFxHairStrands; 29 | class TFxSimulation; 30 | 31 | /* 32 | class EI_Resource; 33 | class EI_Device; 34 | class EI_CommandContext; // ID3D11DeviceContext 35 | class EI_LayoutManager; 36 | struct EI_BindLayout; 37 | class EI_BindSet; 38 | class EI_PSO; 39 | class EI_IndexBuffer; 40 | */ 41 | 42 | // Main API: 43 | class TFxSample { 44 | public: 45 | TFxSample(GlobalState*); 46 | ~TFxSample(); 47 | 48 | // has hardcoded list of resources. other name: load_tfx_assets 49 | void init(); 50 | 51 | // render 52 | void draw_hair(); 53 | // void draw_hair_shadows(); 54 | 55 | // simulation 56 | void simulate(double fTime); 57 | void wait_simulate_done(); 58 | // void draw_collision_mesh(); 59 | 60 | 61 | private: 62 | 63 | // values from GUI etc. 64 | GlobalState* app_state = nullptr; 65 | 66 | // hair strands collection - important! 67 | std::vector m_hairStrands; 68 | 69 | // OIT 70 | TFxPPLL* m_pPPLL = nullptr; 71 | // TFxShortCut* m_pShortCut = nullptr; 72 | // Views for back and depth buffer created in Normal.lua 73 | // SuGPURenderableResourceViewPtr m_pShortCutBackBufferView; 74 | // SuGPUDepthStencilResourceViewPtr m_pShortCutDepthBufferView; 75 | 76 | // Sim 77 | TFxSimulation* m_pSimulation = nullptr; 78 | 79 | // size of PPLL SSBO: PPLLNode[m_nPPLLNodes] 80 | int m_nPPLLNodes = 0; 81 | 82 | // shaders 83 | // SuEffectPtr m_pHairStrandsEffect = nullptr; // oHair.sufx 84 | // (fill linked list) 85 | glUtils::Shader m_shaderPPLL_build; 86 | // SuEffectPtr m_pHairResolveEffect = nullptr; // qHair.sufx 87 | // (render fullscreen quad) 88 | glUtils::Shader m_shaderPPLL_resolve; 89 | 90 | // SuCountedPtr m_pHairColorTexture; 91 | 92 | // Impl: 93 | void load_shaders(); // load_effects 94 | void unload_shaders(); // unload_effects 95 | void initialize_layouts(); 96 | void destroy_layouts(); 97 | }; 98 | 99 | } // namespace glTFx 100 | -------------------------------------------------------------------------------- /src/gl-utils/vao.impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static void bind_buffer_attribute_to_location(u32 location, const glUtils::VertexAttribute&); 4 | 5 | namespace glUtils { 6 | 7 | VertexAttribute::VertexAttribute(const RawBuffer* buffer, 8 | VertexAttributeType type, u32 offset, u32 stride) 9 | : type(type), 10 | buffer(buffer), 11 | offset(offset), 12 | stride(stride) 13 | { 14 | GFX_FAIL_IF(!buffer, "Tried to initialize vertex attribute using non existing buffer(nullptr)"); 15 | } 16 | 17 | VAO create_vao(std::initializer_list attrs) { 18 | VAO vao; 19 | GFX_GL_CALL(glGenVertexArrays, 1, &vao.gl_id); 20 | GFX_GL_CALL(glBindVertexArray, vao.gl_id); 21 | 22 | u32 location = 0; 23 | for (auto &attr : attrs) { 24 | GFX_FAIL_IF(!attr.buffer, "Provided VAO with attribute that does not point to buffer. " 25 | "This is legal in OpenGL (attribute has some default value provided by user), " 26 | "but not implemented in create_vao"); 27 | bind_buffer_attribute_to_location(location, attr); 28 | GFX_GL_CALL(glEnableVertexAttribArray, location); 29 | // TODO store in VAO data for attribs, though why? 30 | // attr.gl_location = location; // if You ever want to read back this value 31 | ++location; 32 | } 33 | 34 | GFX_GL_CALL(glBindVertexArray, 0); 35 | return vao; 36 | } 37 | 38 | void destroy(VAO& vao) { 39 | if (!vao.is_created()) { 40 | return; 41 | } 42 | 43 | // gfx::utils::activate_for_edit(ctxt, &vao); 44 | 45 | // for(u32 i = 0; i < vao.attributes.size(); i++) { 46 | // if (vao.attributes[i].has_buffer()) { 47 | // GFX_GL_CALL(glDisableVertexAttribArray, i); 48 | // } 49 | // } 50 | 51 | GFX_GL_CALL(glDeleteVertexArrays, 1, &vao.gl_id); 52 | 53 | // gfx::utils::activate_for_edit(ctxt, (VAO*) nullptr); 54 | 55 | vao.gl_id = GL_UTILS_NOT_CREATED_ID; 56 | } 57 | 58 | } 59 | 60 | static bool is_integer (GLenum type) { 61 | switch(type) { 62 | case GL_BYTE: 63 | case GL_UNSIGNED_BYTE: 64 | case GL_SHORT: 65 | case GL_UNSIGNED_SHORT: 66 | case GL_INT: 67 | case GL_UNSIGNED_INT: 68 | return true; 69 | default: 70 | return false; 71 | } 72 | } 73 | 74 | void bind_buffer_attribute_to_location(u32 location, const glUtils::VertexAttribute& attr) { 75 | glBindBuffer(glUtils::BufferBindType::VertexBuffer, attr.buffer->gl_id); 76 | 77 | auto offset = (void*)(size_t)attr.offset; 78 | auto gl_type = attr.type.base_type; 79 | auto components = attr.type.components; 80 | 81 | if (is_integer(gl_type)) { 82 | GFX_GL_CALL(glVertexAttribIPointer, 83 | location, components, gl_type, 84 | attr.stride, offset); 85 | } else if (gl_type == GL_DOUBLE) { 86 | GFX_GL_CALL(glVertexAttribLPointer, 87 | location, components, gl_type, 88 | attr.stride, offset); 89 | } else { 90 | GFX_GL_CALL(glVertexAttribPointer, 91 | location, components, gl_type, 92 | GL_FALSE, 93 | attr.stride, offset); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /include/gl-utils/shader/introspect.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace glUtils { 4 | 5 | typedef std::string ShaderResourceName; 6 | typedef unsigned long ShaderResourceNameHash; 7 | 8 | enum class ShaderVariableType { 9 | AttributeIn, AttributeOut, Uniform, BlockMember 10 | }; 11 | 12 | /** 13 | * Represents: 14 | * - Vertex attribute 15 | * - 'standalone' uniforms 16 | * - block members (both ssbo & ubo) 17 | */ 18 | struct ShaderVariable { 19 | ShaderVariableType variable_type; 20 | 21 | /** attribute location, used to address it in all opengl functions like setting value for uniform */ 22 | GLuint gl_location; 23 | 24 | /** gl_index of parent block, or -1 if is_attribute is true or is 'standalone' uniform */ 25 | GLint gl_index_of_parent_block = -1; 26 | 27 | /** 28 | * e.g. GL_FLOAT, GL_INT_VEC2, GL_FLOAT_MAT4, GL_SAMPLER_3D 29 | * (there are a lot of them) 30 | * 31 | * @see table 7.3 on page 114 of OpenGL 4.6 specs 32 | */ 33 | GLenum gl_type; 34 | 35 | /** allowed for uniforms/block members*/ 36 | u32 array_size = 0; 37 | 38 | /** human readable */ 39 | ShaderResourceName name; 40 | ShaderResourceNameHash name_hash; 41 | }; 42 | 43 | struct ShaderBlock { 44 | /** true if ubo, false if ssbo */ 45 | bool is_ubo; 46 | 47 | /** 48 | * Block index, used to address it in all opengl functions. 49 | * This is just global unique id for this block, just as name is human readable 50 | * NOTE: block indices may not be assigned continously / in order they appear in GLSL, 51 | * but they go 0..GL_ACTIVE_UNIFORM_BLOCKS, as indicated by indices. 52 | * TL;DR we get the blocks in random order. 53 | * Source: "uniformBlockIndex is an active uniform block index of program, 54 | * and must be less than the value of GL_ACTIVE_UNIFORM_BLOCKS" 55 | * http://docs.gl/gl4/glGetActiveUniformBlock 56 | */ 57 | GLuint gl_index; 58 | 59 | // is 0 by default and managing it by hand is quite complex 60 | GLuint gl_binding; 61 | 62 | /** size in bytes. Should match sizeof of c++, but may differ depending on packing and vec3 usage*/ 63 | u32 bytes; 64 | 65 | /** human readable */ 66 | ShaderResourceName name; 67 | ShaderResourceNameHash name_hash; 68 | }; 69 | 70 | struct ShaderAtomicUint { 71 | // Always the value of 'binding' from layout attribute 72 | u32 gl_binding; 73 | // Total bytes in binding/slot. Equals to (max_offset + sizeof(uint)). 74 | // This is amount of memory required for underlaying (binded) buffer. 75 | u32 bytes; 76 | // member count, not actually that informative, since the memory required 77 | // depends on max offset (@see bytes). In other words, it is legal to 78 | // have have 3 members, that are at offsets [0, 8, 20]. This would mean 79 | // we need 24 bytes allocated in buffer, despite only using 3 uints. 80 | u32 member_count; 81 | }; 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/gl-utils/uniforms.impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // TODO use glProgramUniform 4 | 5 | #define GET_VARIABLE(VAR_NAME, ...) \ 6 | auto VAR_NAME = sh.get_uniform(name); \ 7 | GFX_FAIL_IF(!VAR_NAME && force, \ 8 | "Tried to set uniform '", name, "', but uniform with this name does not exist. ", \ 9 | "Normally this is allowed, but parameter 'forced' was true, so we crash instead"); \ 10 | if (!VAR_NAME) { return __VA_ARGS__; } 11 | 12 | static void verify_type_match (bool forced, GLenum exp_type, const glUtils::ShaderVariable& var) { 13 | if (!forced) { return; } 14 | GFX_FAIL_IF(exp_type != var.gl_type, "Tried to set uniform '", var.name, "' that has type ", 15 | exp_type, ", but provided ", var.gl_type, ". Check if all types match. " 16 | "Normally this is allowed, but parameter 'forced' was true, so we crash instead"); 17 | } 18 | 19 | namespace glUtils { 20 | 21 | // set uniform: UniformName, void* 22 | u32 set_uniform(const Shader& sh, const UniformName name, void* data, bool force) { 23 | GET_VARIABLE(variable, 0); 24 | return set_uniform(*variable, data); 25 | } 26 | 27 | // set uniform: ShaderVariable, void* 28 | u32 set_uniform(const ShaderVariable& uni, void* data) { 29 | u32 consumed_bytes = 0; 30 | 31 | #define UNIFORM_MACRO(CPP_TYPE, GL_ENUM, GL_SET_FN, VALUE_EXTRACT) \ 32 | case GL_ENUM: glUtils::set_uniform(uni, uniform_convert(data, consumed_bytes)); break; 33 | 34 | switch (uni.gl_type) { 35 | #define UNIFY_UNIFORM_MACRO 36 | #include "../../include/gl-utils/uniform.types.hpp" 37 | 38 | default: 39 | GFX_FAIL("Unsupported uniform type for set_uniform(ShaderVariable, void*), given: ", uni.gl_type); 40 | } 41 | LOGW << "SET void*: " << uni.name << ", loc: " << uni.gl_location; 42 | 43 | #undef UNIFY_UNIFORM_MACRO 44 | #undef UNIFORM_MACRO 45 | 46 | return consumed_bytes; 47 | } 48 | 49 | #define UNIFORM_MACRO(CPP_TYPE, GL_TYPE, GL_SET_FN, VALUE_EXTRACT) \ 50 | void set_uniform(const Shader& sh, const UniformName name, const CPP_TYPE v, bool force){ \ 51 | GET_VARIABLE(variable); set_uniform(*variable, v, force); } \ 52 | void set_uniform(const ShaderVariable& uni, const CPP_TYPE v, bool force) { \ 53 | verify_type_match(force, GL_TYPE, uni); \ 54 | GFX_GL_CALL(GL_SET_FN, uni.gl_location, 1, VALUE_EXTRACT); \ 55 | } 56 | 57 | #define UNIFORM_MACRO_MAT(CPP_TYPE, GL_TYPE, GL_SET_FN, VALUE_EXTRACT) \ 58 | void set_uniform(const Shader& sh, const UniformName name, const CPP_TYPE v, bool transpose, bool force){ \ 59 | GET_VARIABLE(variable); set_uniform(*variable, v, transpose, force); } \ 60 | void set_uniform(const ShaderVariable& uni, const CPP_TYPE v, bool transpose, bool force) { \ 61 | verify_type_match(force, GL_TYPE, uni); \ 62 | GFX_GL_CALL(GL_SET_FN, uni.gl_location, 1, transpose, VALUE_EXTRACT); \ 63 | } 64 | 65 | #include "../../include/gl-utils/uniform.types.hpp" 66 | 67 | #undef UNIFORM_MACRO 68 | #undef UNIFORM_MACRO_MAT 69 | 70 | }; // namespace glUtils 71 | 72 | 73 | #undef GET_VARIABLE 74 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/Math/Matrix44.h: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // File: Matrix44.h 3 | // 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | //-------------------------------------------------------------------------------------- 26 | 27 | #pragma once 28 | 29 | namespace AMD 30 | { 31 | class tressfx_vec3; 32 | 33 | class tressfx_mat44 34 | { 35 | public: 36 | tressfx_mat44(); 37 | tressfx_mat44(const tressfx_mat44& other); 38 | tressfx_mat44(float r1[4], float r2[4], float r3[4], float r4[4]); 39 | tressfx_mat44(float e00, 40 | float e01, 41 | float e02, 42 | float e03, 43 | float e10, 44 | float e11, 45 | float e12, 46 | float e13, 47 | float e20, 48 | float e21, 49 | float e22, 50 | float e23, 51 | float e30, 52 | float e31, 53 | float e32, 54 | float e33); 55 | ~tressfx_mat44(); 56 | 57 | float m[4][4]; 58 | 59 | public: 60 | static const tressfx_mat44 IDENTITY; 61 | static const tressfx_mat44 ZERO; 62 | 63 | public: 64 | void SetIdentity(); 65 | void SetRotation(const tressfx_vec3& axis, float ang); 66 | void SetTranslate(float x, float y, float z); 67 | 68 | float GetElement(int i, int j) const; 69 | 70 | tressfx_vec3 operator*(const tressfx_vec3& vec) const; 71 | tressfx_mat44 operator*(const tressfx_mat44& other) const; 72 | tressfx_mat44& operator=(const tressfx_mat44& other); 73 | 74 | operator float*() const { return (float*)m; } 75 | operator const float*() const { return (const float*)m; } 76 | }; 77 | 78 | } // namespace AMD 79 | -------------------------------------------------------------------------------- /src/gl-tfx/GpuInterface/barriers.impl.hpp: -------------------------------------------------------------------------------- 1 | static const char* debug_EI_ResourceState(AMD::EI_ResourceState st) { 2 | switch (st) { 3 | case AMD::EI_STATE_NON_PS_SRV: return "EI_STATE_NON_PS_SRV"; 4 | case AMD::EI_STATE_VS_SRV: return "EI_STATE_VS_SRV"; 5 | case AMD::EI_STATE_CS_SRV: return "EI_STATE_CS_SRV"; 6 | case AMD::EI_STATE_PS_SRV: return "EI_STATE_PS_SRV"; 7 | case AMD::EI_STATE_UAV: return "EI_STATE_UAV"; 8 | case AMD::EI_STATE_COPY_DEST: return "EI_STATE_COPY_DEST"; 9 | case AMD::EI_STATE_COPY_SOURCE: return "EI_STATE_COPY_SOURCE"; 10 | case AMD::EI_STATE_RENDER_TARGET: return "EI_STATE_RENDER_TARGET"; 11 | } 12 | } 13 | 14 | static void debug_barrier (const AMD::EI_Barrier& bar) { 15 | LOGD << "[TFx_cbSubmitBarriers] " << bar.pResource->name 16 | << "(from=" << debug_EI_ResourceState(bar.from) 17 | << ", to=" << debug_EI_ResourceState(bar.to) 18 | << ")"; 19 | } 20 | 21 | void TFx_cbSubmitBarriers(EI_CommandContextRef context, 22 | int numBarriers, AMD::EI_Barrier* barriers) 23 | { 24 | for (int i = 0; i < numBarriers; ++i) { 25 | auto& bar = barriers[i]; 26 | debug_barrier(bar); 27 | } 28 | 29 | // TODO optimize this, e.g. during load we can forgoe this, 30 | // as we have not executed any GPU code that would change resource memory 31 | if (numBarriers > 0) { 32 | glUtils::async_write_barrier(glUtils::AsyncWriteableResource::All); 33 | } 34 | } 35 | 36 | /* 37 | static SuGPUResource::StateType TranslateState(AMD::EI_ResourceState inState) { 38 | switch (inState) { 39 | case AMD::EI_STATE_NON_PS_SRV: 40 | return SuGPUResource::STATE_NON_PIXEL_SHADER_RESOURCE; 41 | case AMD::EI_STATE_VS_SRV: 42 | return SuGPUResource::STATE_NON_PIXEL_SHADER_RESOURCE; 43 | case AMD::EI_STATE_CS_SRV: 44 | return SuGPUResource::STATE_NON_PIXEL_SHADER_RESOURCE; 45 | case AMD::EI_STATE_PS_SRV: 46 | return SuGPUResource::STATE_PIXEL_SHADER_RESOURCE; 47 | case AMD::EI_STATE_UAV: 48 | return SuGPUResource::STATE_UNORDERED_ACCESS; 49 | case AMD::EI_STATE_COPY_DEST: 50 | return SuGPUResource::STATE_COPY_DEST; 51 | case AMD::EI_STATE_COPY_SOURCE: 52 | return SuGPUResource::STATE_COPY_SOURCE; 53 | case AMD::EI_STATE_RENDER_TARGET: 54 | return SuGPUResource::STATE_RENDER_TARGET; 55 | } 56 | 57 | // fallback. 58 | SuLogWarning("Unknown state."); 59 | return SuGPUResource::STATE_COMMON; 60 | } 61 | 62 | static void SuTransition(EI_Resource* pResource, 63 | AMD::EI_ResourceState from, AMD::EI_ResourceState to) 64 | { 65 | if (from == to) { 66 | if (from == AMD::EI_STATE_UAV) { 67 | pResource->resource->UAVBarrier(); 68 | } else { 69 | SuLogWarning("transition from %d to %d", (int)from, (int)to); 70 | } 71 | } else { 72 | pResource->resource->Transition(TranslateState(from), TranslateState(to)); 73 | } 74 | } 75 | 76 | void SuSubmitBarriers(EI_CommandContextRef context, int numBarriers, AMD::EI_Barrier* barriers) 77 | { 78 | (void)context; 79 | for (int i = 0; i < numBarriers; ++i) 80 | { 81 | SuTransition(barriers[i].pResource, barriers[i].from, barriers[i].to); 82 | } 83 | } 84 | */ 85 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/TressFXSettings.h: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Wrappers for setting values that end up in constant buffers. 3 | // ---------------------------------------------------------------------------- 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | #ifndef _TRESSFXSIMULATIONPARAMS_H_ 27 | #define _TRESSFXSIMULATIONPARAMS_H_ 28 | 29 | // Probably want to unify or rename these. 30 | 31 | // tolua_begin 32 | class TressFXSimulationSettings 33 | { 34 | public: 35 | TressFXSimulationSettings() 36 | : m_vspCoeff(0.8f) 37 | , m_vspAccelThreshold(1.4f) 38 | 39 | , m_localConstraintStiffness(0.9f) 40 | , m_localConstraintsIterations(2) 41 | 42 | , m_globalConstraintStiffness(0.0f) 43 | , m_globalConstraintsRange(0.0f) 44 | 45 | , m_lengthConstraintsIterations(2) 46 | 47 | , m_damping(0.08f) 48 | 49 | , m_gravityMagnitude(10.0) 50 | , m_tipSeparation(0.0f) 51 | 52 | , m_windMagnitude(0) 53 | , m_windAngleRadians(3.1415926f / 180.0f * 40.0f) 54 | { 55 | m_windDirection[0] = 1.0f; 56 | m_windDirection[1] = 0.0f; 57 | m_windDirection[2] = 0.0f; 58 | } 59 | 60 | // VSPf 61 | float m_vspCoeff; 62 | float m_vspAccelThreshold; 63 | 64 | // local constraint 65 | float m_localConstraintStiffness; 66 | int m_localConstraintsIterations; 67 | 68 | // global constraint 69 | float m_globalConstraintStiffness; 70 | float m_globalConstraintsRange; 71 | 72 | // length constraint 73 | int m_lengthConstraintsIterations; 74 | 75 | // damping 76 | float m_damping; 77 | 78 | // gravity 79 | float m_gravityMagnitude; 80 | 81 | // tip separation for follow hair from its guide 82 | float m_tipSeparation; 83 | 84 | // wind 85 | float m_windMagnitude; 86 | float m_windDirection[3]; 87 | float m_windAngleRadians; 88 | }; 89 | // tolua_end 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/scene.impl.hpp: -------------------------------------------------------------------------------- 1 | #include "../libs/tiny_obj_loader/tiny_obj_loader.h" 2 | 3 | struct Geometry { 4 | VAO vao; 5 | RawBuffer vertex_buffer; 6 | RawBuffer index_buffer; 7 | u32 triangles = 0; 8 | }; 9 | 10 | struct SimpleVertex { 11 | glm::vec3 position; 12 | glm::vec3 normal; 13 | }; 14 | 15 | static Geometry create_geometry (const char*const obj_path) { 16 | tinyobj::attrib_t attrib; 17 | std::vector shapes; 18 | 19 | std::string err; 20 | bool ret = tinyobj::LoadObj(&attrib, &shapes, nullptr, &err, obj_path); 21 | GFX_FAIL_IF(!ret || !err.empty(), err); 22 | GFX_FAIL_IF(shapes.size() != 1, ".obj contains != 1 shapes. Please join all models in the scene"); 23 | 24 | const auto& shape = shapes[0]; 25 | const auto& mesh = shape.mesh; 26 | LOGI << "Loaded obj '" << obj_path << "' :: '" << shape.name 27 | << " (vertices=" << attrib.vertices.size() 28 | << ", traingles=" << mesh.indices.size() / 3 << ")"; 29 | 30 | std::vector vertices; 31 | std::vector indices; 32 | 33 | for (size_t i = 0; i < mesh.indices.size(); i++) { 34 | const auto& idx = mesh.indices[i]; 35 | indices.push_back(i); 36 | 37 | const u32 vert_idx = idx.vertex_index * 3; 38 | glm::vec3 pos = { 39 | attrib.vertices[vert_idx], 40 | attrib.vertices[vert_idx + 1], 41 | attrib.vertices[vert_idx + 2] 42 | }; 43 | const u32 norm_idx = idx.normal_index * 3; 44 | glm::vec3 norm = { 45 | attrib.normals[norm_idx], 46 | attrib.normals[norm_idx + 1], 47 | attrib.normals[norm_idx + 2] 48 | }; 49 | 50 | vertices.push_back({ pos, norm }); 51 | } 52 | 53 | Geometry geo; 54 | 55 | // load to gpu 56 | u32 mem_verts = vertices.size() * sizeof(SimpleVertex); 57 | geo.vertex_buffer = glUtils::malloc(mem_verts, BufferUsagePattern::Default); 58 | glUtils::write(geo.vertex_buffer, {0, mem_verts}, &vertices.at(0)); 59 | 60 | // vao 61 | geo.vao = glUtils::create_vao({ 62 | {&geo.vertex_buffer, {GL_FLOAT,3}, 0, sizeof(SimpleVertex)}, // position 63 | {&geo.vertex_buffer, {GL_FLOAT,3}, sizeof(glm::vec3), sizeof(SimpleVertex)} // normals 64 | }); 65 | 66 | // index buffer 67 | geo.triangles = indices.size() / 3; 68 | u32 mem_idx = indices.size() * sizeof(int); 69 | geo.index_buffer = glUtils::malloc(mem_idx, BufferUsagePattern::Default); 70 | glUtils::write(geo.index_buffer, {0, mem_idx}, &indices.at(0)); 71 | 72 | return geo; 73 | } 74 | 75 | static void draw_geometry (const GlobalState& state, const Shader& shader, const Geometry& geo) { 76 | glUseProgram(shader.gl_id); 77 | 78 | // uniforms 79 | const auto& camera = state.camera; 80 | const auto model_mat = state.tfx_settings.model_matrix; 81 | auto mvp = camera.projection * camera.view * model_mat; 82 | glUtils::set_uniform(shader, "g_MVP", mvp); 83 | 84 | // draw 85 | glBindVertexArray(geo.vao.gl_id); 86 | glBindBuffer(glUtils::BufferBindType::IndexBuffer, geo.index_buffer.gl_id); 87 | glDrawElements(GL_TRIANGLES, geo.triangles * 3, GL_UNSIGNED_INT, nullptr); 88 | } 89 | 90 | static void destroy_geometry(Geometry& geo) { 91 | destroy(geo.vao); 92 | destroy(geo.vertex_buffer); 93 | destroy(geo.index_buffer); 94 | } 95 | -------------------------------------------------------------------------------- /include/gl-utils/sync.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace glUtils { 4 | 5 | /** 6 | There are certain GPU operations that do not affect memory (buffers/textures) in synchronous manner. 7 | This means that when we write to memory in such manner, the next operation may not receive updated result. 8 | This is known as "incoherent memory accesses". It includes following operations: 9 | - writes (atomic or otherwise) via Image Load Store (RandomAccessTexture) 10 | - writes (atomic or otherwise) via Shader Storage Buffer Objects (SSBO) 11 | - writes to variables declared as shared in Compute Shaders (but not output variables in Tessellation Control Shaders) 12 | This means that before we read the value, we have to synchronize using glMemoryBarier with appropriate bits set. 13 | Each mode says how we READ the opengl object. E.g. we write to raw memory, but then we interpret this memory 14 | during READ as BufferDrawCommand - that would require call to glMemoryBarier with 15 | GL_COMMAND_BARRIER_BIT (or gfx::async_write_barrier(AsyncWriteableResource::BufferDrawCommand)) 16 | 17 | NOTE: memoryBarier is GLSL function. glMemoryBarier is opengl function. Be careful when reading the docs 18 | 19 | @see https://www.khronos.org/opengl/wiki/Memory_Model 20 | @see https://www.khronos.org/opengl/wiki/GLAPI/glMemoryBarrier 21 | */ 22 | struct AsyncWriteableResource { 23 | // we write to buffer as e.g. SSBO, the use this buffer as: 24 | static const GLenum BufferVertex = GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT; 25 | static const GLenum BufferIndices = GL_ELEMENT_ARRAY_BARRIER_BIT; 26 | static const GLenum BufferUbo = GL_UNIFORM_BARRIER_BIT; 27 | static const GLenum BufferDrawCommand = GL_COMMAND_BARRIER_BIT; // GL_DRAW_INDIRECT_BUFFER and GL_DISPATCH_INDIRECT_BUFFER 28 | static const GLenum BufferPixels = GL_PIXEL_BUFFER_BARRIER_BIT; // GL_PIXEL_PACK_BUFFER and GL_PIXEL_UNPACK_BUFFER 29 | static const GLenum BufferQuery = GL_QUERY_BUFFER_BARRIER_BIT; // (v>=44) 30 | static const GLenum BufferAtomic = GL_ATOMIC_COUNTER_BARRIER_BIT; 31 | static const GLenum BufferSsbo = GL_SHADER_STORAGE_BARRIER_BIT; // (v>=43) 32 | static const GLenum BufferTransformFeedback = GL_TRANSFORM_FEEDBACK_BARRIER_BIT; 33 | static const GLenum BufferAllOps = GL_BUFFER_UPDATE_BARRIER_BIT; 34 | 35 | // textures - write using Image load/store technique (RandomAccessTexture) 36 | static const GLenum RandomAccessTexture = GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; // Image load/store 37 | static const GLenum Framebuffer = GL_FRAMEBUFFER_BARRIER_BIT; // ?we can async write to texture that is fbo and then we have to wait for it to be visible? 38 | static const GLenum Texture = GL_TEXTURE_FETCH_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT; // Texture e.g. buffer textures 39 | // Texture eg.glTex(Sub)Image*, glCopyTex(Sub)Image*, glClearTex*Image, glCompressedTex(Sub)Image*, glGetTexImage 40 | 41 | // Other 42 | static const GLenum MappedBuffer = GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT; // when buffer is mapped, we need to wait for wrtite-through to read async changes 43 | static const GLenum All = GL_ALL_BARRIER_BITS; 44 | }; 45 | typedef GLenum AsyncWriteableResource_; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /libs/amd_tressfx/src/Math/Transform.cpp: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // File: Transform.cpp 3 | // 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | //-------------------------------------------------------------------------------------- 26 | 27 | #include "Math/Transform.h" 28 | 29 | namespace AMD 30 | { 31 | tressfx_transform::tressfx_transform(void) {} 32 | 33 | tressfx_transform::tressfx_transform(const tressfx_transform& other) 34 | { 35 | m_Translation = other.m_Translation; 36 | m_Rotation = other.m_Rotation; 37 | } 38 | 39 | tressfx_transform::tressfx_transform(const tressfx_vec3& translation, 40 | const tressfx_quat& rotation) 41 | { 42 | m_Translation = translation; 43 | m_Rotation = rotation; 44 | } 45 | 46 | tressfx_transform::~tressfx_transform(void) {} 47 | 48 | void tressfx_transform::Inverse() 49 | { 50 | m_Rotation.Inverse(); 51 | m_Translation = m_Rotation * (-m_Translation); 52 | } 53 | 54 | tressfx_transform tressfx_transform::InverseOther() const 55 | { 56 | tressfx_transform other(*this); 57 | other.Inverse(); 58 | return other; 59 | } 60 | 61 | tressfx_vec3 tressfx_transform::operator*(const tressfx_vec3& vector) const 62 | { 63 | return m_Rotation * vector + m_Translation; 64 | } 65 | 66 | tressfx_transform tressfx_transform::operator*(const tressfx_transform& transform) const 67 | { 68 | return tressfx_transform(m_Rotation * transform.GetTranslation() + m_Translation, 69 | m_Rotation * transform.GetRotation()); 70 | } 71 | 72 | tressfx_transform& tressfx_transform::operator=(const tressfx_transform& other) 73 | { 74 | if (this == &other) 75 | { 76 | return (*this); 77 | } 78 | 79 | m_Translation = other.m_Translation; 80 | m_Rotation = other.m_Rotation; 81 | 82 | return (*this); 83 | } 84 | 85 | } // namespace AMD 86 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(TressFx) 3 | 4 | include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Utils.cmake) 5 | include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake) 6 | 7 | 8 | # OPTIONS 9 | set_with_default(CMAKE_BUILD_TYPE Release STRING "Choose the type of build (Debug or Release)") 10 | assert_one_of(CMAKE_BUILD_TYPE Release Debug) 11 | 12 | 13 | # VERSION 14 | set(VERSION_MAJOR 1) 15 | set(VERSION_MINOR 0) 16 | set(VERSION_PATCH 0) 17 | 18 | 19 | # Print current project settings 20 | message("CMAKE_GENERATOR: ${CMAKE_GENERATOR}") 21 | message("CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") 22 | message("CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}") 23 | message("Architecture: ${M_ARCH_NAME}") 24 | message("Complier: ${M_COMPILER_NAME}") 25 | message("Project: ${CMAKE_PROJECT_NAME} v${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") 26 | 27 | 28 | # EXECUTABLE 29 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 30 | 31 | # do not include "src/main.cpp" in SOURCE_FILES, as it conflicts with tests 32 | file(GLOB_RECURSE SOURCE_FILES "src/*.cpp") 33 | file(GLOB_RECURSE LIBS_FILES "libs/*.cpp") 34 | add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${LIBS_FILES} "src/main.cpp") 35 | # add_executable(${PROJECT_NAME} ${SOURCE_FILES} "src/main.cpp") 36 | 37 | # set(TESTS_TARGET "tests") 38 | # file(GLOB_RECURSE TEST_FILES "tests/*.cpp") 39 | # add_executable(${TESTS_TARGET} EXCLUDE_FROM_ALL ${SOURCE_FILES} ${TEST_FILES}) 40 | 41 | 42 | # COMPILER & LINKER 43 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic ${M_CPP_17_COMPILER_FLAG}") 44 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem \"libs/amd_tressfx/include\"") # add TFx to include dirs (required by AMD lib impl) 45 | 46 | if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") 47 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -D DEBUG -O0 -gdwarf-2") # flag for debug 48 | endif() 49 | 50 | # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -std=c++1z -lstdc++" ) 51 | target_link_libraries(${PROJECT_NAME} ${M_ADDITIONAL_LIBS}) 52 | # target_link_libraries(${TESTS_TARGET} ${M_ADDITIONAL_LIBS}) 53 | 54 | 55 | # LIBS 56 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules) 57 | 58 | find_package(GLM REQUIRED) 59 | include_directories(PUBLIC ${GLM_INCLUDE_DIRS}) 60 | 61 | find_package(SDL2 REQUIRED) 62 | include_directories(PUBLIC ${SDL2_INCLUDE_DIRS}) 63 | target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARY}) 64 | # target_link_libraries(${TESTS_TARGET} ${SDL2_LIBRARY}) 65 | 66 | find_package(GLAD REQUIRED) 67 | include_directories(PUBLIC ${GLAD_INCLUDE_DIRS}) 68 | target_link_libraries(${PROJECT_NAME} ${GLAD_LIBRARY}) 69 | # target_link_libraries(${TESTS_TARGET} ${GLAD_LIBRARY}) 70 | 71 | # PREPROCESSOR 72 | #add_definitions(-DUSE_BROFILER) 73 | 74 | 75 | # Define Options 76 | # option(OPTION_ENABLE_BROFILER "Enable Brofiler profiler support" ON) 77 | 78 | 79 | #set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin") 80 | 81 | #if (OPTION_ENABLE_BROFILER) 82 | # add_definitions(-DUSE_BROFILER) 83 | # include_directories( ${SDK_DIR}/Brofiler ) 84 | # link_directories( ${SDK_DIR}/Brofiler ) 85 | # set(COMMON_LIBS ${COMMON_LIBS} ProfilerCore64) 86 | #endif() 87 | 88 | #if (WIN32) 89 | # add_subdirectory(Code/Launcher/DedicatedLauncher) 90 | # add_subdirectory(Code/Launcher/WindowsLauncher) 91 | #endif () 92 | -------------------------------------------------------------------------------- /src/gl-utils/shader/shader.impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "compile.impl.hpp" 4 | #include "introspect.impl.hpp" 5 | 6 | static const glUtils::ShaderVariable* get_var(glUtils::ShaderResourceName, 7 | glUtils::ShaderVariableType*, const glUtils::ShaderVariables&); 8 | 9 | namespace glUtils { 10 | 11 | Shader create_shader(const ShaderTexts& texts, ShaderErrorsScratchpad& es) { 12 | Shader shader; 13 | shader.gl_id = GFX_GL_CALL(glCreateProgram); 14 | 15 | if (!compile_program(texts, shader.gl_id, es)) { 16 | destroy(shader); 17 | return shader; 18 | } 19 | 20 | auto res_cnt = get_resource_count(shader.gl_id); 21 | read_attributes(shader.gl_id, shader.used_variables, res_cnt.attr_in, ShaderVariableType::AttributeIn); 22 | read_attributes(shader.gl_id, shader.used_variables, res_cnt.attr_out, ShaderVariableType::AttributeOut); 23 | read_blocks(shader.gl_id, shader.used_blocks, res_cnt.ubo, true); 24 | read_blocks(shader.gl_id, shader.used_blocks, res_cnt.ssbo, false); 25 | read_uniforms_and_block_members(shader.gl_id, shader.used_variables, res_cnt.all_uniforms, true); 26 | read_uniforms_and_block_members(shader.gl_id, shader.used_variables, res_cnt.ssbo_members, false); 27 | read_atomics(shader.gl_id, shader.used_atomics, res_cnt.atomics); 28 | 29 | return shader; 30 | } 31 | 32 | void destroy(Shader& shader) { 33 | if (!shader.is_created()) { 34 | return; 35 | } 36 | 37 | glUseProgram(0); // ugh, just in case.. 38 | GFX_GL_CALL(glDeleteProgram, shader.gl_id); 39 | 40 | shader.gl_id = GL_UTILS_NOT_CREATED_ID; 41 | } 42 | 43 | 44 | const ShaderVariable* Shader::get_attribute(ShaderResourceName name) const noexcept { 45 | ShaderVariableType svt[] = {ShaderVariableType::AttributeIn, ShaderVariableType::AttributeOut}; 46 | return get_var(name, svt, this->used_variables); 47 | } 48 | 49 | const ShaderVariable* Shader::get_uniform(ShaderResourceName name) const noexcept { 50 | ShaderVariableType svt[] = {ShaderVariableType::Uniform, ShaderVariableType::Uniform}; // :) 51 | return get_var(name, svt, this->used_variables); 52 | } 53 | 54 | ShaderBlock* Shader::get_block(ShaderResourceName name, bool is_ubo) noexcept { 55 | auto hash = shader_name_hash(name); 56 | glUtils::ShaderBlock* result = nullptr; 57 | 58 | for (auto& v : this->used_blocks) { 59 | if (v.is_ubo == is_ubo && v.name_hash == hash) { 60 | result = &v; 61 | } 62 | } 63 | 64 | return result; 65 | } 66 | 67 | const ShaderAtomicUint* Shader::get_atomic(u32 gl_binding) const noexcept { 68 | const ShaderAtomicUint* result = nullptr; 69 | 70 | for (const auto& v : this->used_atomics) { 71 | if (v.gl_binding == gl_binding) { 72 | result = &v; 73 | } 74 | } 75 | 76 | return result; 77 | } 78 | 79 | } // namespace glUtils 80 | 81 | const glUtils::ShaderVariable* get_var(glUtils::ShaderResourceName name, glUtils::ShaderVariableType* types, 82 | const glUtils::ShaderVariables& variables) 83 | { 84 | auto hash = shader_name_hash(name); 85 | const glUtils::ShaderVariable* result = nullptr; 86 | 87 | for (const auto& v : variables) { 88 | bool match_type = v.variable_type == types[0] 89 | || v.variable_type == types[1]; 90 | if (match_type && v.name_hash == hash) { 91 | result = &v; 92 | } 93 | } 94 | 95 | return result; 96 | } 97 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/sim/_SimQuat.comp.glsl: -------------------------------------------------------------------------------- 1 | // START _SimQuat.glsl 2 | 3 | vec4 MakeQuaternion(float angle_radian, vec3 axis) 4 | { 5 | // create quaternion using angle and rotation axis 6 | vec4 quaternion; 7 | float halfAngle = 0.5f * angle_radian; 8 | float sinHalf = sin(halfAngle); 9 | 10 | quaternion.w = cos(halfAngle); 11 | quaternion.xyz = sinHalf * axis.xyz; 12 | 13 | return quaternion; 14 | } 15 | 16 | // Makes a quaternion from a 4x4 column major rigid transform matrix. Rigid transform means that rotational 3x3 sub matrix is orthonormal. 17 | // Note that this function does not check the orthonormality. 18 | vec4 MakeQuaternion(/*column_major*/ mat4 m) 19 | { 20 | vec4 q; 21 | float trace = m[0][0] + m[1][1] + m[2][2]; 22 | 23 | if (trace > 0.0f) 24 | { 25 | float r = sqrt(trace + 1.0f); 26 | q.w = 0.5 * r; 27 | r = 0.5 / r; 28 | q.x = (m[1][2] - m[2][1])*r; 29 | q.y = (m[2][0] - m[0][2])*r; 30 | q.z = (m[0][1] - m[1][0])*r; 31 | } 32 | else 33 | { 34 | int i = 0, j = 1, k = 2; 35 | 36 | if (m[1][1] > m[0][0]) 37 | { 38 | i = 1; j = 2; k = 0; 39 | } 40 | if (m[2][2] > m[i][i]) 41 | { 42 | i = 2; j = 0; k = 1; 43 | } 44 | 45 | float r = sqrt(m[i][i] - m[j][j] - m[k][k] + 1.0f); 46 | 47 | float qq[4]; 48 | 49 | qq[i] = 0.5f * r; 50 | r = 0.5f / r; 51 | q.w = (m[j][k] - m[k][j])*r; 52 | qq[j] = (m[j][i] + m[i][j])*r; 53 | qq[k] = (m[k][i] + m[i][k])*r; 54 | 55 | q.x = qq[0]; q.y = qq[1]; q.z = qq[2]; 56 | } 57 | 58 | return q; 59 | } 60 | 61 | vec4 InverseQuaternion(vec4 q) 62 | { 63 | float lengthSqr = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; 64 | 65 | if ( lengthSqr < 0.001 ) 66 | return vec4(0, 0, 0, 1.0f); 67 | 68 | q.x = -q.x / lengthSqr; 69 | q.y = -q.y / lengthSqr; 70 | q.z = -q.z / lengthSqr; 71 | q.w = q.w / lengthSqr; 72 | 73 | return q; 74 | } 75 | 76 | vec3 MultQuaternionAndVector(vec4 q, vec3 v) 77 | { 78 | vec3 uv, uuv; 79 | vec3 qvec = vec3(q.x, q.y, q.z); 80 | uv = cross(qvec, v); 81 | uuv = cross(qvec, uv); 82 | uv *= (2.0f * q.w); 83 | uuv *= 2.0f; 84 | 85 | return v + uv + uuv; 86 | } 87 | 88 | vec4 MultQuaternionAndQuaternion(vec4 qA, vec4 qB) 89 | { 90 | vec4 q; 91 | 92 | q.w = qA.w * qB.w - qA.x * qB.x - qA.y * qB.y - qA.z * qB.z; 93 | q.x = qA.w * qB.x + qA.x * qB.w + qA.y * qB.z - qA.z * qB.y; 94 | q.y = qA.w * qB.y + qA.y * qB.w + qA.z * qB.x - qA.x * qB.z; 95 | q.z = qA.w * qB.z + qA.z * qB.w + qA.x * qB.y - qA.y * qB.x; 96 | 97 | return q; 98 | } 99 | 100 | vec4 NormalizeQuaternion(vec4 q) 101 | { 102 | vec4 qq = q; 103 | float n = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; 104 | 105 | if (n < 1e-10f) 106 | { 107 | qq.w = 1; 108 | return qq; 109 | } 110 | 111 | qq *= 1.0f / sqrt(n); 112 | return qq; 113 | } 114 | 115 | // Compute a quaternion which rotates u to v. u and v must be unit vector. 116 | vec4 QuatFromTwoUnitVectors(vec3 u, vec3 v) 117 | { 118 | float r = 1.f + dot(u, v); 119 | vec3 n; 120 | 121 | // if u and v are parallel 122 | if (r < 1e-7) 123 | { 124 | r = 0.0f; 125 | n = abs(u.x) > abs(u.z) ? vec3(-u.y, u.x, 0.f) : vec3(0.f, -u.z, u.y); 126 | } 127 | else 128 | { 129 | n = cross(u, v); 130 | } 131 | 132 | vec4 q = vec4(n.x, n.y, n.z, r); 133 | return NormalizeQuaternion(q); 134 | } 135 | 136 | // END _SimQuat.glsl 137 | -------------------------------------------------------------------------------- /include/gl-utils/draw/blend.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace glUtils { 4 | 5 | /** @see https://github.com/glium/glium/blob/cd1bab4f6b7c3b48391289b3a10be115f660b252/src/draw_parameters/blend.rs#L123 for good overview */ 6 | struct BlendingFactor { 7 | static const GLenum Zero = GL_ZERO; // nope 8 | static const GLenum One = GL_ONE; // replace 9 | // static const GLenum SourceAlphaSaturate = GL_SRC_ALPHA_SATURATE; // use GL_SRC_ALPHA_SATURATE instead of BlendingFactor::_ 10 | 11 | static const GLenum SourceColor = GL_SRC_COLOR;// src 12 | static const GLenum OneMinusSourceColor = GL_ONE_MINUS_SRC_COLOR;// 1-src 13 | static const GLenum DestinationColor = GL_DST_COLOR;// dest 14 | static const GLenum OneMinusDestinationColor = GL_ONE_MINUS_DST_COLOR;// 1-dest 15 | static const GLenum ConstantColor = GL_CONSTANT_COLOR; // C 16 | static const GLenum OneMinusConstantColor = GL_ONE_MINUS_CONSTANT_COLOR; // 1-C 17 | 18 | static const GLenum SourceAlpha = GL_SRC_ALPHA; // Alpha: src 19 | static const GLenum OneMinusSourceAlpha = GL_ONE_MINUS_SRC_ALPHA; // Alpha: 1-src 20 | static const GLenum DestinationAlpha = GL_DST_ALPHA; // Alpha: dest 21 | static const GLenum OneMinusDestinationAlpha = GL_ONE_MINUS_DST_ALPHA; // Alpha: 1-dest 22 | static const GLenum ConstantAlpha = GL_CONSTANT_ALPHA; // Alpha: C 23 | static const GLenum OneMinusConstantAlpha = GL_ONE_MINUS_CONSTANT_ALPHA; // Alpha: 1-C 24 | }; 25 | typedef GLenum BlendingFactor_; 26 | 27 | /** @see https://github.com/glium/glium/blob/cd1bab4f6b7c3b48391289b3a10be115f660b252/src/draw_parameters/blend.rs#L55 for good overview */ 28 | struct BlendingFunction { 29 | static const GLenum AlwaysReplace = GL_NONE; // dummy value, will be handled manually 30 | static const GLenum Min = GL_MIN; 31 | static const GLenum Max = GL_MAX; 32 | static const GLenum Addition = GL_FUNC_ADD; 33 | static const GLenum Subtraction = GL_FUNC_SUBTRACT; 34 | static const GLenum ReverseSubtraction = GL_FUNC_REVERSE_SUBTRACT; 35 | }; 36 | typedef GLenum BlendingFunction_; 37 | 38 | struct BlendingMode { 39 | BlendingFunction_ function = BlendingFunction::AlwaysReplace; 40 | 41 | /** destination color (the one that is already on texture) */ 42 | BlendingFactor_ current_value_factor = BlendingFactor::Zero; 43 | 44 | /** source color (the one from pixel shader) */ 45 | BlendingFactor_ new_value_factor = BlendingFactor::One; 46 | }; 47 | 48 | struct Blend { 49 | BlendingMode color; 50 | BlendingMode alpha; 51 | glm::vec4 constant_value = {1.0, 1.0, 1.0, 1.0}; 52 | }; 53 | 54 | inline bool operator==(const BlendingMode& a, const BlendingMode& b) { 55 | return (a.function == b.function) 56 | && (a.current_value_factor == b.current_value_factor) 57 | && (a.new_value_factor == b.new_value_factor); 58 | } 59 | inline bool operator!=(const BlendingMode& a, const BlendingMode& b) { 60 | return !(a == b); 61 | } 62 | 63 | inline bool operator==(const Blend& a, const Blend& b) { 64 | return (a.alpha == b.alpha) 65 | && (a.color == b.color) 66 | && (a.constant_value == b.constant_value); 67 | } 68 | inline bool operator!=(const Blend& a, const Blend& b) { 69 | return !(a == b); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /bin/build_glsl.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | import subprocess 4 | from os import path 5 | 6 | SHADERS_DIR = 'src/shaders' 7 | SHADERS_OUT_DIR = 'src/shaders/generated' 8 | 9 | SHADER_FILES = [ 10 | 'gl-tfx/ppll_build.vert.glsl', 11 | 'gl-tfx/ppll_build.frag.glsl', 12 | 'gl-tfx/ppll_resolve.vert.glsl', 13 | 'gl-tfx/ppll_resolve.frag.glsl', 14 | 'gl-tfx/sim0_IntegrationAndGlobalShapeConstraints.comp.glsl', 15 | 'gl-tfx/sim1_VelocityShockPropagation.comp.glsl', 16 | 'gl-tfx/sim2_LocalShapeConstraints.comp.glsl', 17 | 'gl-tfx/sim3_LengthConstraintsWindAndCollision.comp.glsl', 18 | 'gl-tfx/sim4_UpdateFollowHairVertices.comp.glsl' 19 | ] 20 | 21 | INCLUDE_REGEX = '^#pragma include "(.*?)"' 22 | NVIDIA_ERR_REGEX = '^.*\((.*?)\).:.(.*?) .+?: (.*)$' 23 | 24 | 25 | class Colors: 26 | BLACK = '\033[0;{}m'.format(30) 27 | RED = '\033[0;{}m'.format(31) 28 | GREEN = '\033[0;{}m'.format(32) 29 | YELLOW = '\033[0;{}m'.format(33) 30 | BLUE = '\033[0;{}m'.format(34) 31 | MAGENTA = '\033[0;{}m'.format(35) 32 | CYAN = '\033[0;{}m'.format(36) 33 | WHITE = '\033[0;{}m'.format(37) 34 | 35 | def process_file(filepath): 36 | buf = [] 37 | with open(filepath) as f: 38 | lines = f.readlines() 39 | for line in lines: 40 | included_file = re.search(INCLUDE_REGEX, line, re.IGNORECASE) 41 | if included_file: 42 | file_to_include = path.join(path.dirname(filepath), included_file.group(1)) 43 | print(' include: ', file_to_include) 44 | buf.extend(process_file(file_to_include)) 45 | else: 46 | buf.append(line) 47 | return buf 48 | 49 | def process_error_line(err_line, shader_lines): 50 | matches = re.search(NVIDIA_ERR_REGEX, err_line, re.IGNORECASE) 51 | if matches: 52 | line_no, level, msg = int(matches.group(1)), matches.group(2), matches.group(3) 53 | line = shader_lines[line_no - 1].strip() 54 | is_warn = level == 'warning' 55 | col = Colors.YELLOW if is_warn else Colors.RED 56 | level_str = 'Warn' if is_warn else 'Err' 57 | 58 | print('{}[L{}] {}: {}'.format(col, line_no, level_str, msg)) 59 | print('{} > {}{}'.format(Colors.CYAN, line, Colors.WHITE)) 60 | else: 61 | print(err_line) 62 | 63 | def test_compile(filepath, shader_lines): 64 | ret = subprocess.check_output([ 65 | 'bin\glslcompiler\GLSLCompiler.exe', 66 | filepath, 67 | '-iconic' # 'silences' freeglut window 68 | ]).decode("utf-8") 69 | # print(Colors.RED, str(ret), Colors.WHITE) 70 | 71 | if 'success!' in ret.lower(): 72 | return True 73 | 74 | err_lines = ret.split('\n') 75 | print(Colors.RED, err_lines[0].strip(), Colors.WHITE) 76 | for line in err_lines[1:]: 77 | process_error_line(line, shader_lines) 78 | return False 79 | 80 | if __name__ == '__main__': 81 | has_error = False 82 | for filepath in SHADER_FILES: 83 | in_path = path.join(SHADERS_DIR, filepath) 84 | out_path = path.join(SHADERS_OUT_DIR, filepath) 85 | print(in_path, ' => ', out_path) 86 | 87 | after_processing = process_file(in_path) 88 | new_file_content = ''.join(after_processing) 89 | 90 | with open(out_path, 'w') as f: 91 | f.write(new_file_content) 92 | 93 | has_error = has_error or not test_compile(out_path, after_processing) 94 | # break 95 | 96 | if has_error: 97 | sys.exit(1) 98 | print() 99 | -------------------------------------------------------------------------------- /include/pch.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // TODO actually use as pch 4 | 5 | // #include 6 | #include 7 | 8 | /// 9 | /// types 10 | #include 11 | typedef int8_t i8; 12 | typedef uint8_t u8; 13 | typedef int16_t i16; 14 | typedef uint16_t u16; 15 | typedef int32_t i32; 16 | typedef uint32_t u32; 17 | typedef int64_t i64; 18 | typedef uint64_t u64; 19 | typedef float f32; 20 | typedef double f64; 21 | 22 | 23 | /// 24 | /// macros 25 | 26 | #define STRINGIFY_(s) #s 27 | #define STRINGIFY(s) STRINGIFY_(s) 28 | 29 | /* This will let macros expand before concating them */ 30 | #define CONCAT_(x, y) x ## y 31 | #define CONCAT(x, y) CONCAT_(x, y) 32 | 33 | #define UNUSED(x) (void)(x) 34 | 35 | /* This counts the number of args */ 36 | #define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,N,...) N 37 | #define NARGS(...) NARGS_SEQ(__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 38 | 39 | /* This will call a macro on each argument passed in */ 40 | #define APPLY(macro, ...) CONCAT(APPLY_, NARGS(__VA_ARGS__))(macro, __VA_ARGS__) 41 | #define APPLY_1(m, x1) m(x1) 42 | #define APPLY_2(m, x1, x2) m(x1) m(x2) 43 | #define APPLY_3(m, x1, x2, x3) m(x1) m(x2) m(x3) 44 | #define APPLY_4(m, x1, x2, x3, x4) m(x1) m(x2) m(x3) m(x4) 45 | #define APPLY_5(m, x1, x2, x3, x4, x5) m(x1) m(x2) m(x3) m(x4) m(x5) 46 | #define APPLY_6(m, x1, x2, x3, x4, x5, x6) m(x1) m(x2) m(x3) m(x4) m(x5) m(x6) 47 | #define APPLY_7(m, x1, x2, x3, x4, x5, x6, x7) m(x1) m(x2) m(x3) m(x4) m(x5) m(x6) m(x7) 48 | #define APPLY_8(m, x1, x2, x3, x4, x5, x6, x7, x8) m(x1) m(x2) m(x3) m(x4) m(x5) m(x6) m(x7) m(x8) 49 | #define APPLY_9(m, x1, x2, x3, x4, x5, x6, x7, x8, x9) m(x1) m(x2) m(x3) m(x4) m(x5) m(x6) m(x7) m(x8) m(x9) 50 | #define APPLY_10(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) m(x1) m(x2) m(x3) m(x4) m(x5) m(x6) m(x7) m(x8) m(x9) m(x10) 51 | #define APPLY_11(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) m(x1) m(x2) m(x3) m(x4) m(x5) m(x6) m(x7) m(x8) m(x9) m(x10) m(x11) 52 | #define APPLY_12(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) m(x1) m(x2) m(x3) m(x4) m(x5) m(x6) m(x7) m(x8) m(x9) m(x10) m(x11) m(x12) 53 | 54 | 55 | 56 | /* 57 | /// 58 | /// Breakpoint from code 59 | 60 | namespace utils { 61 | bool is_debugger_present(); 62 | } 63 | 64 | #if defined(_MSC_VER) && (_MSC_VER >= 1300) 65 | #define DEBUG_BREAK() if (::utils::is_debugger_present()){ __debugbreak();} 66 | #else 67 | #define DEBUG_BREAK() if (::utils::is_debugger_present()){ asm("int3");} 68 | #endif 69 | */ 70 | 71 | /// 72 | /// enum class utils 73 | #include 74 | 75 | template 76 | constexpr std::size_t enum_count() noexcept { 77 | static_assert(std::is_enum::value, "Not an enum" ); 78 | return static_cast< std::size_t >( enumeration::Count ); 79 | } 80 | 81 | template 82 | constexpr std::size_t enum_int(const enumeration value) noexcept { 83 | static_assert(std::is_enum::value, "Not an enum" ); 84 | return static_cast< std::size_t>(value); 85 | } 86 | 87 | template 88 | constexpr enumeration int_enum(const std::size_t value) noexcept { 89 | return static_cast(value); 90 | } 91 | 92 | 93 | /// 94 | /// functions / classes 95 | #include "logging/Logger.hpp" 96 | #include "gl-utils/main.hpp" 97 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/Math/Quaternion.h: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // File: Quaternion.h 3 | // 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | //-------------------------------------------------------------------------------------- 26 | 27 | #pragma once 28 | 29 | #include "Matrix33.h" 30 | #include "Vector3D.h" 31 | 32 | #pragma warning(push) 33 | #pragma warning( \ 34 | disable : 4201) // disable warning C4201: nonstandard extension used : nameless struct/union 35 | 36 | namespace AMD 37 | { 38 | class tressfx_quat 39 | { 40 | public: 41 | tressfx_quat(float x = 0.0, float y = 0.0, float z = 0.0, float w = 1.0); 42 | tressfx_quat(const tressfx_quat& other); 43 | tressfx_quat(const tressfx_mat33& rotMat); 44 | tressfx_quat(const tressfx_vec3& axis, float angle_radian); 45 | tressfx_quat(float* xyz); 46 | ~tressfx_quat(void); 47 | 48 | public: 49 | union 50 | { 51 | struct 52 | { 53 | float m[4]; 54 | }; // x, y, z, w 55 | struct 56 | { 57 | float x, y, z, w; 58 | }; 59 | }; 60 | 61 | tressfx_quat& Normalize(); 62 | 63 | void SetRotation(const tressfx_vec3& axis, float angle_radian); 64 | void SetRotation(const tressfx_mat33& rotMat); 65 | void SetRotation(const tressfx_quat& quaternion); 66 | void GetRotation(tressfx_vec3* pAxis, float* pAngle_radian) const; 67 | void GetRotation(tressfx_mat33* pMat33) const; 68 | tressfx_mat33 GetMatrix33() const; 69 | float Length() const; 70 | 71 | void SetIdentity(); 72 | void Inverse(); 73 | tressfx_quat InverseOther() const; 74 | 75 | tressfx_quat& operator=(const tressfx_quat& other); 76 | tressfx_quat& operator=(float* xyz); 77 | tressfx_quat operator+(const tressfx_quat& other) const; 78 | tressfx_quat operator+(const tressfx_vec3& vec) const; 79 | tressfx_quat operator*(const tressfx_quat& other) const; 80 | tressfx_vec3 operator*(const tressfx_vec3& vec) const; 81 | 82 | friend tressfx_vec3 operator*(const tressfx_vec3& vec, const tressfx_quat& q); 83 | }; 84 | 85 | } // namespace AMD 86 | 87 | #pragma warning(pop) 88 | -------------------------------------------------------------------------------- /libs/amd_tressfx/src/TressFXFileFormat.h: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------------------- 2 | // Header file that defines the .tfx binary file format. This is the format that will 3 | // be exported by authoring tools, and is the standard file format for hair data. The game 4 | // can either read this file directly, or further procsessing can be done offline to improve 5 | // load times. 6 | //------------------------------------------------------------------------------------- 7 | // 8 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | // THE SOFTWARE. 27 | // 28 | 29 | 30 | 31 | #pragma once 32 | 33 | // 34 | // TressFXTFXFileHeader Structure 35 | // 36 | // This structure defines the header of the file. The actual vertex data follows this as specified by the offsets. 37 | struct TressFXTFXFileHeader 38 | { 39 | float version; // Specifies TressFX version number 40 | unsigned int numHairStrands; // Number of hair strands in this file. All strands in this file are guide strands. 41 | // Follow hair strands are generated procedurally. 42 | unsigned int numVerticesPerStrand; // From 4 to 64 inclusive (POW2 only). This should be a fixed value within tfx value. 43 | // The total vertices from the tfx file is numHairStrands * numVerticesPerStrand. 44 | 45 | // Offsets to array data starts here. Offset values are in bytes, aligned on 8 bytes boundaries, 46 | // and relative to beginning of the .tfx file 47 | unsigned int offsetVertexPosition; // Array size: FLOAT4[numHairStrands] 48 | unsigned int offsetStrandUV; // Array size: FLOAT2[numHairStrands], if 0 no texture coordinates 49 | unsigned int offsetVertexUV; // Array size: FLOAT2[numHairStrands * numVerticesPerStrand], if 0, no per vertex texture coordinates 50 | unsigned int offsetStrandThickness; // Array size: float[numHairStrands] 51 | unsigned int offsetVertexColor; // Array size: FLOAT4[numHairStrands * numVerticesPerStrand], if 0, no vertex colors 52 | 53 | unsigned int reserved[32]; // Reserved for future versions 54 | }; 55 | 56 | 57 | struct TressFXTFXBoneFileHeader 58 | { 59 | float version; 60 | unsigned int numHairStrands; 61 | unsigned int numInfluenceBones; 62 | unsigned int offsetBoneNames; 63 | unsigned int offsetSkinningData; 64 | unsigned int reserved[32]; 65 | }; -------------------------------------------------------------------------------- /include/gl-utils/texture/TextureOpts.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace glUtils { 4 | 5 | struct TextureFilterMin { 6 | static const GLenum Nearest = GL_NEAREST; 7 | static const GLenum Linear = GL_LINEAR; 8 | static const GLenum NearestMipmapNearest = GL_NEAREST_MIPMAP_NEAREST; 9 | static const GLenum LinearMipmapNearest = GL_LINEAR_MIPMAP_NEAREST; 10 | static const GLenum NearestMipmapLinear = GL_NEAREST_MIPMAP_LINEAR; 11 | static const GLenum LinearMipmapLinear = GL_LINEAR_MIPMAP_LINEAR; 12 | }; 13 | typedef GLenum TextureFilterMin_; 14 | 15 | struct TextureFilterMag { 16 | static const GLenum Nearest = GL_NEAREST; 17 | static const GLenum Linear = GL_LINEAR; 18 | }; 19 | typedef GLenum TextureFilterMag_; 20 | 21 | /* 22 | struct TextureCompareFn { 23 | static const GLenum Lequal = GL_LEQUAL; 24 | static const GLenum Gequal = GL_GEQUAL; 25 | static const GLenum Less = GL_LESS; 26 | static const GLenum Greater = GL_GREATER; 27 | static const GLenum Equal = GL_EQUAL; 28 | static const GLenum Not_equal = GL_NOTEQUAL; 29 | static const GLenum Always = GL_ALWAYS; 30 | static const GLenum Never = GL_NEVER; 31 | static const GLenum None = GL_NONE; //GL_TEXTURE_COMPARE_MODE == GL_NONE 32 | }; 33 | typedef GLenum TextureCompareFn_; 34 | */ 35 | 36 | struct TextureSwizzle { 37 | static const GLenum Red = GL_RED; 38 | static const GLenum Green = GL_GREEN; 39 | static const GLenum Blue = GL_BLUE; 40 | static const GLenum Alpha = GL_ALPHA; 41 | static const GLenum Zero = GL_ZERO; 42 | static const GLenum One = GL_ONE; 43 | }; 44 | typedef GLenum TextureSwizzle_; 45 | 46 | struct TextureWrap { 47 | static const GLenum UseEdgePixel = GL_CLAMP_TO_EDGE; 48 | static const GLenum UseBorderColor = GL_CLAMP_TO_BORDER; 49 | static const GLenum MirroredRepeat = GL_MIRRORED_REPEAT; 50 | static const GLenum Repeat = GL_REPEAT; 51 | static const GLenum MirrorThenUseEdgePixel = GL_MIRROR_CLAMP_TO_EDGE; 52 | }; 53 | typedef GLenum TextureWrap_; 54 | 55 | /** 56 | * @see http://docs.gl/gl4/glTexParameter#Description 57 | */ 58 | struct TextureOpts { 59 | /** GL_DEPTH_STENCIL_TEXTURE_MODE (it true will read depth, if false will read stencil) TODO should be set dynamically per read basis?*/ 60 | // bool read_depth_if_depth_stencil = true; 61 | /** GL_TEXTURE_BASE_LEVEL */ 62 | u32 mipmap_min = 0; 63 | /** GL_TEXTURE_MAX_LEVEL */ 64 | u32 mipmap_max = 0; 65 | /** GL_TEXTURE_BORDER_COLOR, order: RGBA */ 66 | u32 border_color[4] = {0,0,0,0}; // 67 | /** GL_TEXTURE_COMPARE_FUNC */ 68 | // TextureCompareFn_ depth_compare_fn = TextureCompareFn::None; 69 | /** GL_TEXTURE_MIN_FILTER */ 70 | TextureFilterMin_ filter_min = TextureFilterMin::Linear; 71 | /** GL_TEXTURE_MAG_FILTER */ 72 | TextureFilterMag_ filter_mag = TextureFilterMag::Linear; 73 | /** GL_TEXTURE_MIN_LOD, */ 74 | i32 lod_min = -1000; 75 | /** GL_TEXTURE_MAX_LOD, */ 76 | i32 lod_max = 1000; 77 | /** GL_TEXTURE_LOD_BIAS, must be < GL_MAX_TEXTURE_LOD_BIAS */ 78 | f32 lod_bias = 0.0; 79 | /** GL_TEXTURE_SWIZZLE_RGBA, GL_TEXTURE_SWIZZLE_R, GL_TEXTURE_SWIZZLE_G, GL_TEXTURE_SWIZZLE_B, GL_TEXTURE_SWIZZLE_A, */ 80 | TextureSwizzle_ swizzle[4] = { 81 | TextureSwizzle::Red, 82 | TextureSwizzle::Green, 83 | TextureSwizzle::Blue, 84 | TextureSwizzle::Alpha 85 | }; 86 | /** GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_TEXTURE_WRAP_R. */ 87 | TextureWrap_ wrap[3] = { 88 | TextureWrap::Repeat, 89 | TextureWrap::Repeat, 90 | TextureWrap::Repeat 91 | }; 92 | }; 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/gl-tfx/TFxSimulation.cpp: -------------------------------------------------------------------------------- 1 | #include "../../include/pch.hpp" 2 | #include "TFxSimulation.hpp" 3 | 4 | #include "../../libs/amd_tressfx/include/TressFXLayouts.h" 5 | #include "TFxHairStrands.hpp" 6 | #include "GpuInterface/TFxGpuInterface.hpp" 7 | // #include "SDF.h" 8 | #include "../State.hpp" 9 | 10 | // #include "SushiGPUInterface.h" 11 | // #include "SuEffectManager.h" 12 | 13 | 14 | static auto SIM_0_SHADER_PATH = "sim0_IntegrationAndGlobalShapeConstraints.comp.glsl"; 15 | static auto SIM_1_SHADER_PATH = "sim1_VelocityShockPropagation.comp.glsl"; 16 | static auto SIM_2_SHADER_PATH = "sim2_LocalShapeConstraints.comp.glsl"; 17 | static auto SIM_3_SHADER_PATH = "sim3_LengthConstraintsWindAndCollision.comp.glsl"; 18 | static auto SIM_4_SHADER_PATH = "sim4_UpdateFollowHairVertices.comp.glsl"; 19 | 20 | static void load_compute_shader (EI_LayoutManager& slm, const char*const path, glUtils::Shader* shader) { 21 | glUtils::ShaderTexts st; 22 | st.compute = path; 23 | glTFx::load_tfx_shader(*shader, st); 24 | slm.shaders.push_back({shader, path, ""}); 25 | } 26 | 27 | namespace glTFx { 28 | 29 | TFxSimulation::TFxSimulation() { 30 | EI_Device* pDevice = (EI_Device*)GetDevice(); 31 | 32 | // load shaders 33 | EI_LayoutManager slm; 34 | load_compute_shader(slm, SIM_0_SHADER_PATH, &shader_sim0_IntegrationAndGlobalShapeConstraints); 35 | load_compute_shader(slm, SIM_1_SHADER_PATH, &shader_sim1_VelocityShockPropagation); 36 | load_compute_shader(slm, SIM_2_SHADER_PATH, &shader_sim2_LocalShapeConstraints); 37 | load_compute_shader(slm, SIM_3_SHADER_PATH, &shader_sim3_LengthConstraintsWindAndCollision); 38 | load_compute_shader(slm, SIM_4_SHADER_PATH, &shader_sim4_UpdateFollowHairVertices); 39 | 40 | // EI_LayoutManagerRef simLayoutManager = GetLayoutManagerRef(m_pTressFXSimEffect); 41 | // EI_LayoutManager simLayoutManager = {&this->m_shaderPPLL_resolve, PPLL_RESOLVE_VS_PATH, PPLL_RESOLVE_FS_PATH}; 42 | CreateSimPosTanLayout2(pDevice, slm); 43 | CreateSimLayout2(pDevice, slm); 44 | 45 | // init AMD lib 46 | mSimulation.Initialize(pDevice, slm); 47 | } 48 | 49 | TFxSimulation::~TFxSimulation() { 50 | EI_Device* pDevice = GetDevice(); 51 | 52 | mSimulation.Shutdown(pDevice); 53 | 54 | glUtils::destroy(shader_sim0_IntegrationAndGlobalShapeConstraints); 55 | glUtils::destroy(shader_sim1_VelocityShockPropagation); 56 | glUtils::destroy(shader_sim2_LocalShapeConstraints); 57 | glUtils::destroy(shader_sim3_LengthConstraintsWindAndCollision); 58 | glUtils::destroy(shader_sim4_UpdateFollowHairVertices); 59 | } 60 | 61 | void TFxSimulation::start_simulation(double /*fTime*/, std::vector& hairStrands) { 62 | // SuCommandListPtr pSimCommandList = m_ComputeQueue.GetComputeCommandList(); 63 | // EI_CommandContextRef simContext = (EI_CommandContextRef)pSimCommandList; 64 | EI_CommandContextRef simContext = GetContext(); 65 | 66 | // run 67 | for (size_t i = 0; i < hairStrands.size(); i++) { 68 | simContext.simulated_hair_object = hairStrands[i]->get_AMDTressFXHandle(); 69 | 70 | // update bone matrices for bone skinning of first two vertices of hair strands 71 | // hairStrands[i]->UpdateBones(simContext); 72 | 73 | // Run simulation 74 | hairStrands[i]->simulate(simContext, &mSimulation); 75 | } 76 | 77 | // finalize 78 | for (size_t i = 0; i < hairStrands.size(); i++){ 79 | hairStrands[i]->TransitionSimToRendering(simContext); 80 | } 81 | 82 | // Have compute work wait for signal from graphics queue that we can start 83 | // issuing the sim commands. 84 | // m_ComputeQueue.WaitForLastFrameHairRenders(); 85 | // m_ComputeQueue.SubmitSimCommandList(pSimCommandList); 86 | // m_ComputeQueue.RestoreRenderAsDefaultQueue(pRenderCommandList); 87 | } 88 | 89 | void TFxSimulation::wait_on_simulation() { 90 | // m_ComputeQueue.WaitForCompute(); 91 | } 92 | 93 | } // namespace glTFx 94 | -------------------------------------------------------------------------------- /src/gl-utils/debug_callback.impl.hpp: -------------------------------------------------------------------------------- 1 | 2 | static glUtils::DebugBehaviourForType debugBehaviourType; 3 | 4 | static glUtils::DebugBehaviourForSeverity get_by_debug_msg_type (GLenum type) { 5 | switch (type) { 6 | case GL_DEBUG_TYPE_ERROR: return debugBehaviourType.error; 7 | case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return debugBehaviourType.deprecated_behavior; 8 | case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return debugBehaviourType.undefined_behavior; 9 | case GL_DEBUG_TYPE_PORTABILITY: return debugBehaviourType.portability; 10 | case GL_DEBUG_TYPE_PERFORMANCE: return debugBehaviourType.performance; 11 | case GL_DEBUG_TYPE_MARKER: return debugBehaviourType.marker; 12 | case GL_DEBUG_TYPE_PUSH_GROUP: return debugBehaviourType.push_group; 13 | case GL_DEBUG_TYPE_POP_GROUP: return debugBehaviourType.pop_group; 14 | default: return debugBehaviourType.other; 15 | } 16 | } 17 | 18 | static const char* to_str_type (GLenum type) { 19 | switch (type) { 20 | case GL_DEBUG_TYPE_ERROR: return "error"; 21 | case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "deprecated_behavior"; 22 | case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "undefined_behavior"; 23 | case GL_DEBUG_TYPE_PORTABILITY: return "portability"; 24 | case GL_DEBUG_TYPE_PERFORMANCE: return "performance"; 25 | case GL_DEBUG_TYPE_MARKER: return "marker"; 26 | case GL_DEBUG_TYPE_PUSH_GROUP: return "push_group"; 27 | case GL_DEBUG_TYPE_POP_GROUP: return "pop_group"; 28 | default: return "other"; 29 | } 30 | } 31 | 32 | static const char* to_str_source (GLenum type) { 33 | switch (type) { 34 | case GL_DEBUG_SOURCE_API: return "api"; 35 | case GL_DEBUG_SOURCE_WINDOW_SYSTEM: return "window_system"; 36 | case GL_DEBUG_SOURCE_SHADER_COMPILER: return "shader_compiler"; 37 | case GL_DEBUG_SOURCE_APPLICATION: return "application"; 38 | case GL_DEBUG_SOURCE_THIRD_PARTY: return "third_party"; 39 | default: return "other"; 40 | } 41 | } 42 | 43 | static const char* to_str_severity (GLenum type) { 44 | switch (type) { 45 | case GL_DEBUG_SEVERITY_LOW: return "low"; 46 | case GL_DEBUG_SEVERITY_MEDIUM: return "medium"; 47 | case GL_DEBUG_SEVERITY_HIGH: return "high"; 48 | } 49 | return "NOT_VALID"; 50 | } 51 | 52 | void debug_callback (GLenum source, GLenum type, GLuint id, 53 | GLenum severity, GLsizei, const GLchar *message, 54 | const void *) 55 | { 56 | using namespace glUtils; 57 | auto behOpts = get_by_debug_msg_type(type); 58 | DebugBehaviour beh = severity == GL_DEBUG_SEVERITY_HIGH ? behOpts.high 59 | : severity == GL_DEBUG_SEVERITY_MEDIUM ? behOpts.medium : behOpts.low; 60 | 61 | // beh = DebugBehaviour::AsDebug; 62 | if (beh == DebugBehaviour::Skip) { 63 | return; 64 | } 65 | 66 | std::string msg = std::string("[GlDebugCallback ") 67 | + to_str_source(source) + "." 68 | + to_str_type(type) + "." 69 | + to_str_severity(severity) 70 | + " id=" + std::to_string(id) + "]: " + message; 71 | 72 | switch (beh) { 73 | case DebugBehaviour::Skip: break; 74 | case DebugBehaviour::AsDebug: LOGD << msg; break; 75 | case DebugBehaviour::AsInfo: LOGI << msg; break; 76 | case DebugBehaviour::AsError: LOGE << msg; break; 77 | case DebugBehaviour::Critical: 78 | LOGE << msg; 79 | GFX_FAIL("Received critical message from gl_debug_callback. See above for details"); 80 | break; 81 | } 82 | } 83 | 84 | namespace glUtils { 85 | 86 | void init_debug_callback(const glUtils::DebugBehaviourForType& beh) { 87 | glEnable(GL_DEBUG_OUTPUT); 88 | glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); // hmm.. TODO remove for optimization? or just use 4.6 no errors mode? 89 | debugBehaviourType = beh; 90 | glDebugMessageCallback(debug_callback, nullptr); 91 | } 92 | 93 | } // namespace glUtils 94 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/TressFXPPLL.h: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Interface for TressFX OIT using per-pixel linked lists. 3 | // ---------------------------------------------------------------------------- 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | #ifndef AMD_TRESSFXPPLL_H 27 | #define AMD_TRESSFXPPLL_H 28 | 29 | 30 | #include "TressFXGPUInterface.h" 31 | 32 | // By default, TressFX node sizes are 16 bytes. 4 bytes for each of: tangentcoverage, depth, 33 | // baseColor, next pointer 34 | #define TRESSFX_DEFAULT_NODE_SIZE 16 35 | 36 | // The special value meaning "end of list" in the PPLL. 37 | // So the UAV of head pointers gets cleared to this. 38 | #define TRESSFX_PPLL_NULL_PTR 0xffffffff 39 | 40 | // This is the interface the engine uses to call TressFX at a high level. 41 | // There are basically two steps each frame. 42 | // In the first, hair strands are rendered, accumulating the fragments in 43 | // the PPLL: 44 | // BindForBuild() 45 | // [Draws hair] 46 | // DoneBuilding() 47 | // 48 | // In the second, the fragments are gathered and blended into the backbuffer. 49 | // BindForRead() 50 | // [Draw screen pass] 51 | // DoneReading() 52 | // 53 | class TressFXPPLL 54 | { 55 | public: 56 | TressFXPPLL(); 57 | ~TressFXPPLL(); 58 | 59 | // node size should include room for UINT next pointer. 60 | bool Create(EI_Device* pDevice, 61 | int width, 62 | int height, 63 | int nNodes, 64 | int nodeSize = TRESSFX_DEFAULT_NODE_SIZE); 65 | void Destroy(EI_Device* context); 66 | 67 | void Clear(EI_CommandContextRef context); 68 | 69 | 70 | // These might get removed. 71 | // Do we want to gather the bindings to be sent for each 72 | // draw, or just bind once? 73 | void BindForBuild(EI_CommandContextRef commandContext); 74 | void BindForRead(EI_CommandContextRef context); 75 | 76 | // The "dones" should not require a layout if it's just a transition, 77 | // but this is an opportunity for unbinding. 78 | void DoneBuilding(EI_CommandContextRef context); 79 | void DoneReading(EI_CommandContextRef context); 80 | 81 | private: 82 | int m_nScreenWidth; 83 | int m_nScreenHeight; 84 | int m_nNodes; 85 | int m_nNodeSize; 86 | 87 | // We track whether the current PPLL is valid 88 | // so the engine implementation doesn't have to. 89 | bool m_bCreated; 90 | 91 | EI_RWTexture2D* m_pHeads; 92 | EI_StructuredBuffer* m_pNodes; 93 | 94 | void CreateBuildBindSet(EI_Device* pDevice); 95 | void CreateReadBindSet(EI_Device* pDevice); 96 | 97 | 98 | EI_BindSet* m_pPPLLBuildBindSet; 99 | EI_BindSet* m_pPPLLReadBindSet; 100 | }; 101 | 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /src/logging/formatter.impl.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // #include 4 | 5 | // Available patterns: 6 | // - %h - hours 7 | // - %m - minutes 8 | // - %s - seconds 9 | // - %p - log level (shortened to D/I/W/E) 10 | // - %f - filename 11 | // - %l - line 12 | // 13 | // e.g. 14 | // - "%h:%m:%s %f:%l [%p] " 15 | // - "%f:%l [%p] "; 16 | logger::LogImpl::LogPattern logger::LogImpl::Pattern = "%f:%l [%p] "; 17 | 18 | const char* level_symbol[] = {"T", "D","I","W","E"}; 19 | 20 | static logger::ColorFg_ get_color_by_level (logger::LogLevel); 21 | static void set_color (std::ostringstream&, logger::ColorFg_); 22 | static void add_symbol(char, std::ostringstream&, const logger::MsgMetaData&); 23 | 24 | #define LOC_ACCURACY 5 25 | #define FILENAME_LETTERS 25 26 | 27 | namespace logger { 28 | 29 | 30 | struct MsgMetaData { 31 | logger::LogLevel level; 32 | const char* const file_name; 33 | int line; 34 | std::tm* time; 35 | }; 36 | 37 | LogImpl& Log::get(const char* const file_name, const int line, LogLevel level){ 38 | std::time_t t = std::time(0); 39 | impl->set_header({level, file_name, line, std::localtime(&t)}); 40 | return *impl; 41 | } 42 | 43 | void LogImpl::set_header(const MsgMetaData& meta) { 44 | auto pattern = LogImpl::Pattern; 45 | 46 | // os << color_by_level(meta.level); 47 | set_color(this->os, get_color_by_level(meta.level)); 48 | 49 | char* it = const_cast(pattern); 50 | while(*it != '\0'){ 51 | if(*it == '%'){ 52 | ++it; 53 | add_symbol(*it, os, meta); 54 | } else { 55 | os << *it; 56 | } 57 | 58 | ++it; 59 | } 60 | 61 | set_color(this->os, ColorFg::White); 62 | } 63 | 64 | } 65 | 66 | static char* get_filename(const char* const fullpath) { 67 | // extracts filename from path 68 | auto s1 = strrchr(fullpath, '/'), 69 | s2 = strrchr(fullpath, '\\'); 70 | char* last_slash = const_cast(fullpath); 71 | 72 | if (s1 && s1 > s2) { 73 | last_slash = s1 + 1; 74 | } else if (s2) { 75 | last_slash = s2 + 1; 76 | } 77 | 78 | return last_slash; 79 | } 80 | 81 | static void put_exactly (std::ostringstream& os, char* str_to_add, unsigned int to_put) { 82 | auto len = strlen(str_to_add); 83 | if (len > to_put) { 84 | str_to_add += len - to_put; 85 | } 86 | 87 | os << str_to_add; 88 | 89 | for (size_t i = len; i < to_put; i++) { 90 | os << ' '; 91 | } 92 | } 93 | 94 | void add_symbol(char it, std::ostringstream& os, const logger::MsgMetaData& data){ 95 | switch(it){ 96 | case 'h': // hour 97 | os << data.time->tm_hour; 98 | break; 99 | case 'm': // minutes 100 | os << data.time->tm_min; 101 | break; 102 | case 's': // seconds 103 | os << data.time->tm_sec; 104 | break; 105 | case 'p': // log level 106 | os << level_symbol[data.level]; 107 | break; 108 | case 'f': // file 109 | // os << get_filename(data.file_name); 110 | put_exactly(os, get_filename(data.file_name), FILENAME_LETTERS); 111 | break; 112 | case 'l':{ // line number 113 | char pat[] = {'%', '0','d', '\0'}; 114 | pat[1] += LOC_ACCURACY - 1; 115 | char buffer[LOC_ACCURACY+1]; 116 | snprintf(buffer, LOC_ACCURACY, pat, data.line); 117 | os << buffer; 118 | break;} 119 | default: 120 | os << '%'; break; 121 | } 122 | } 123 | 124 | logger::ColorFg_ get_color_by_level (logger::LogLevel lvl) { 125 | switch(lvl) { 126 | case logger::LogLevel::Trace: return logger::ColorFg::Magenta; // Cyan? 127 | case logger::LogLevel::Debug: return logger::ColorFg::Green; 128 | case logger::LogLevel::Info: return logger::ColorFg::Blue; 129 | case logger::LogLevel::Warning: return logger::ColorFg::Yellow; 130 | case logger::LogLevel::Error: return logger::ColorFg::Red; 131 | } 132 | } 133 | 134 | static void set_color (std::ostringstream& os, logger::ColorFg_ col) { 135 | os << "\033[0;" << col << "m"; 136 | } 137 | -------------------------------------------------------------------------------- /include/gl-utils/draw/stencil.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace glUtils { 4 | 5 | struct StencilTest { 6 | static const GLenum AlwaysPass = GL_ALWAYS; 7 | static const GLenum AlwaysFail = GL_NEVER; 8 | static const GLenum IfRefIsLessThenCurrent = GL_LESS; // write if this->reference_value < current_stencil_value 9 | static const GLenum IfRefIsLessOrEqualCurrent = GL_LEQUAL; 10 | static const GLenum IfRefIsMoreThenCurrent = GL_GREATER; // write if this->reference_value > current_stencil_value 11 | static const GLenum IfRefIsMoreOrEqualCurrent = GL_GEQUAL; 12 | static const GLenum IfRefIsEqualCurrent = GL_EQUAL; // write if this->reference_value == current_stencil_value 13 | static const GLenum IfRefIsNotEqualCurrent = GL_NOTEQUAL; // write if this->reference_value != current_stencil_value 14 | }; 15 | typedef GLenum StencilTest_; 16 | 17 | struct StencilOperation { 18 | static const GLenum Keep = GL_KEEP; // keep current value 19 | static const GLenum Zero = GL_ZERO; // write zero 20 | static const GLenum Replace = GL_REPLACE; // write reference value 21 | static const GLenum Increment = GL_INCR; // min(current_value + 1, MAX_INT) 22 | static const GLenum IncrementWrap = GL_INCR_WRAP; // let next = current_value + 1; return next == MAX_INT ? 0 : next 23 | static const GLenum Decrement = GL_DECR; // max(current_value - 1, MIN_INT) 24 | static const GLenum DecrementWrap = GL_DECR_WRAP; // let next = current_value - 1; return current_value == 0 ? MAX_INT : next 25 | static const GLenum Invert = GL_INVERT; // invert bits 26 | }; 27 | typedef GLenum StencilOperation_; 28 | 29 | struct StencilPerSide { 30 | /** Comparison against the existing value in the stencil buffer. */ 31 | StencilTest_ test = StencilTest::AlwaysPass; 32 | 33 | /** Specifies the operation to do when a fragment fails the stencil test. */ 34 | StencilOperation_ op_stencil_fail = StencilOperation::Keep; 35 | 36 | /** Specifies the operation to do when a fragment passes the stencil test but fails the depth test.*/ 37 | StencilOperation_ op_stencil_pass_depth_fail = StencilOperation::Keep; 38 | 39 | /** Specifies the operation to do when a fragment passes both the stencil and depth tests. */ 40 | StencilOperation_ op_pass = StencilOperation::Keep; 41 | }; 42 | 43 | 44 | /** 45 | * Stencil test procedure: 46 | * (StencilRefVal & CompareMask) CompTestFunc (StencilBufferValue & CompareMask) 47 | * Stencil write new value procedure: 48 | * (~StencilWriteMask & StencilBufferValue) | (StencilWriteMask & StencilOp(StencilBufferValue)) 49 | * 50 | * Inspired by D3D11_DEPTH_STENCIL_DESC 51 | */ 52 | struct Stencil { 53 | /** 54 | * Reference value, can be used to: 55 | * * compare to in stencil test 56 | * * write to stencil buffer (StencilOperation::Replace) 57 | */ 58 | GLint reference_value = 0; 59 | 60 | /** used for compare, see last arg to glStencilFunc. Also known as ReadMask */ 61 | GLuint compare_mask = 0xffffffff; 62 | 63 | /** Allows specifying a mask when writing data on the stencil buffer. Also known as WriteMask */ 64 | GLuint write_bytes = 0xffffffff; 65 | 66 | StencilPerSide front; 67 | StencilPerSide back; 68 | }; 69 | 70 | inline bool operator==(const StencilPerSide& a, const StencilPerSide& b) { 71 | return (a.test == b.test) 72 | && (a.op_stencil_fail == b.op_stencil_fail) 73 | && (a.op_stencil_pass_depth_fail == b.op_stencil_pass_depth_fail) 74 | && (a.op_pass == b.op_pass); 75 | } 76 | inline bool operator!=(const StencilPerSide& a, const StencilPerSide& b) { 77 | return !(a == b); 78 | } 79 | 80 | inline bool operator==(const Stencil& a, const Stencil& b) { 81 | return (a.reference_value == b.reference_value) 82 | && (a.compare_mask == b.compare_mask) 83 | && (a.write_bytes == b.write_bytes) 84 | && (a.front == b.front) 85 | && (a.back == b.back); 86 | } 87 | inline bool operator!=(const Stencil& a, const Stencil& b) { 88 | return !(a == b); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/gl-utils/texture/allocate_texture.impl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ARB_texture_storage (core 4.2) provides immutable textures whose definition is complete up-front. 4 | // The classic glTexImage never "knew" how many mip-maps would actually be specified, 5 | // often causing lazy allocation. glTextureStorage is the better alternative for the driver. 6 | // glTextureStorage produces immutable memory boundaries 7 | 8 | static void allocate_storage (const glUtils::Texture& texture); 9 | 10 | namespace glUtils { 11 | 12 | void allocate_texture(Texture& texture, bool apply_texture_options) { 13 | GFX_GL_CALL(glCreateTextures, texture.gl_type, 1, &texture.gl_id); 14 | 15 | allocate_storage(texture); 16 | 17 | if (apply_texture_options) { 18 | glUtils::apply_texture_options(texture, texture.opts); 19 | } 20 | } 21 | 22 | void destroy(Texture& texture) { 23 | if (!texture.is_created()) { 24 | return; 25 | } 26 | 27 | GFX_GL_CALL(glDeleteTextures, 1, &texture.gl_id); 28 | 29 | texture.gl_id = GL_UTILS_NOT_CREATED_ID; 30 | } 31 | 32 | } // namespace glUtils 33 | 34 | static void verify_dimension (const u32*const& dims, const u32 to_check) { 35 | GFX_FAIL_IF(to_check > 3, "Tried to verify dimension of 4D texture? WHAT?!"); 36 | const char* order_sufix[3] = {"st", "nd", "rd"}; 37 | 38 | for (size_t i = 0; i < to_check; i++) { 39 | GFX_FAIL_IF(dims[i] == 0, "Tried to allocate ", to_check, 40 | " dimensional texture, but ", (i+1), order_sufix[i], " dimension (or multisample) is 0"); 41 | } 42 | } 43 | 44 | static bool is_3d(const glUtils::Texture& texture) { 45 | return texture.gl_type == GL_TEXTURE_3D 46 | || texture.gl_type == GL_TEXTURE_2D_ARRAY 47 | || texture.gl_type == GL_TEXTURE_CUBE_MAP_ARRAY; 48 | } 49 | 50 | static bool is_2d(const glUtils::Texture& texture) { 51 | return texture.gl_type == GL_TEXTURE_2D 52 | || texture.gl_type == GL_TEXTURE_1D_ARRAY 53 | || texture.gl_type == GL_TEXTURE_CUBE_MAP; 54 | } 55 | 56 | static bool is_1d(const glUtils::Texture& texture) { 57 | return texture.gl_type == GL_TEXTURE_1D; 58 | } 59 | 60 | void allocate_storage (const glUtils::Texture& texture) { 61 | const u32* dimensions = texture.dimensions; 62 | auto gl_id = texture.gl_id; 63 | auto mipmap_levels = texture.mipmap_levels + 1; 64 | auto storage_internal_format = texture.sized_pixel_format; 65 | 66 | // multisample related 67 | bool ms_fixedsamplelocations = GL_TRUE; 68 | auto ms_sample_count = texture.multisample; 69 | 70 | if (is_3d(texture)) { 71 | verify_dimension(dimensions, 3); 72 | GFX_GL_CALL(glTextureStorage3D, gl_id, mipmap_levels, storage_internal_format, 73 | dimensions[0], dimensions[1], dimensions[2]); 74 | 75 | } else if (is_2d(texture)) { 76 | verify_dimension(dimensions, 2); 77 | GFX_GL_CALL(glTextureStorage2D, gl_id, mipmap_levels, storage_internal_format, 78 | dimensions[0], dimensions[1]); 79 | 80 | } else if (is_1d(texture)) { 81 | verify_dimension(dimensions, 1); 82 | GFX_GL_CALL(glTextureStorage1D, gl_id, mipmap_levels, storage_internal_format, 83 | dimensions[0]); 84 | 85 | } else if (texture.gl_type == GL_TEXTURE_2D_MULTISAMPLE) { 86 | verify_dimension(dimensions, 2); 87 | verify_dimension(&ms_sample_count, 1); 88 | GFX_GL_CALL(glTextureStorage2DMultisample, gl_id, ms_sample_count, storage_internal_format, 89 | dimensions[0], dimensions[1], ms_fixedsamplelocations); 90 | 91 | } else if (texture.gl_type == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { 92 | verify_dimension(dimensions, 3); 93 | verify_dimension(&ms_sample_count, 1); 94 | GFX_GL_CALL(glTextureStorage3DMultisample, gl_id, ms_sample_count, storage_internal_format, 95 | dimensions[0], dimensions[1], dimensions[2], ms_fixedsamplelocations); 96 | 97 | } else { 98 | GFX_FAIL("Tried to allocate_texture using unsupported texture type " 99 | "(probably GL_TEXTURE_RECTANGLE or GL_TEXTURE_BUFFER or GL_PROXY_TEXTURE_* or some compressed type)"); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/Math/Matrix33.h: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // File: Matrix33.h 3 | // 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | //-------------------------------------------------------------------------------------- 26 | 27 | #pragma once 28 | 29 | namespace AMD 30 | { 31 | class tressfx_vec3; 32 | 33 | class tressfx_mat33 34 | { 35 | friend class tressfx_vec3; 36 | friend class tressfx_quat; 37 | 38 | public: 39 | tressfx_mat33(void); 40 | tressfx_mat33(const tressfx_mat33& other); 41 | tressfx_mat33(float e00, 42 | float e01, 43 | float e02, 44 | float e10, 45 | float e11, 46 | float e12, 47 | float e20, 48 | float e21, 49 | float e22); 50 | ~tressfx_mat33(void); 51 | 52 | private: 53 | float m[3][3]; 54 | 55 | public: 56 | static const tressfx_mat33 IDENTITY; 57 | static const tressfx_mat33 ZERO; 58 | 59 | public: 60 | void SetIdentity(); 61 | void Set(float e00, 62 | float e01, 63 | float e02, 64 | float e10, 65 | float e11, 66 | float e12, 67 | float e20, 68 | float e21, 69 | float e22); 70 | float GetElement(int i, int j) const; 71 | void SetElement(int i, int j, float val); 72 | void SetRotation(const tressfx_vec3& axis, float ang); 73 | void Inverse(); 74 | tressfx_mat33 InverseOther() const; 75 | void Transpose(); 76 | tressfx_mat33 TransposeOther() const; 77 | 78 | tressfx_vec3 operator*(const tressfx_vec3& vec) const; 79 | tressfx_mat33 operator*(const tressfx_mat33& other) const; 80 | tressfx_mat33 operator*(float val) const; 81 | tressfx_mat33 operator+(const tressfx_mat33& other) const; 82 | tressfx_mat33 operator-(const tressfx_mat33& other) const; 83 | tressfx_mat33 operator/(float val) const; 84 | tressfx_mat33& operator*=(float val); 85 | tressfx_mat33& operator-=(const tressfx_mat33& other); 86 | tressfx_mat33& operator+=(const tressfx_mat33& other); 87 | tressfx_mat33& operator=(const tressfx_mat33& other); 88 | 89 | bool operator==(const tressfx_mat33& other); 90 | bool operator!=(const tressfx_mat33& other); 91 | 92 | bool operator==(float a); 93 | bool operator!=(float a); 94 | 95 | float& operator()(int i, int j); 96 | const float& operator()(int i, int j) const; 97 | 98 | friend tressfx_mat33 operator*(float val, const tressfx_mat33& other); 99 | friend tressfx_mat33 operator-(const tressfx_mat33& other); 100 | }; 101 | 102 | } // namespace AMD 103 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/sim1_VelocityShockPropagation.comp.glsl: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | #pragma include "_utils.glsl" 4 | #pragma include "sim/_SimParams.comp.glsl" 5 | #pragma include "sim/_SimCommon.comp.glsl" 6 | #pragma include "sim/_SimBuffers.comp.glsl" 7 | #pragma include "sim/_SimQuat.comp.glsl" 8 | 9 | // Propagate velocity shock resulted by attached based mesh 10 | // 1) Calculate (rotation + translation) that root strand vertex was subjected to 11 | // 2) Propagate (rotation + translation) from parent to child vertices in same strand, 12 | // using vspCoeff(set as uniform in simulation settings) as a weight 13 | // 3) Write values to g_HairVertexPositions_, g_HairVertexPositionsPrev_ 14 | // for child vertices 15 | // 16 | // One thread computes one strand. 17 | // 18 | layout (local_size_x = THREAD_GROUP_SIZE) in; // [numthreads(THREAD_GROUP_SIZE, 1, 1)] 19 | void main() { 20 | uint local_id, group_id, globalStrandIndex, numVerticesInTheStrand, globalRootVertexIndex, strandType; 21 | CalcIndicesInStrandLevelMaster(gl_LocalInvocationIndex, gl_WorkGroupID.x, globalStrandIndex, numVerticesInTheStrand, globalRootVertexIndex, strandType); 22 | 23 | // since one thread == one strand, we base the work on (root) -> (root+1) vertices 24 | vec4 pos_old_old[2]; // *previous previous* positions for vertex 0 (root) and vertex 1. 25 | vec4 pos_old[2]; // *previous* positions for vertex 0 (root) and vertex 1. 26 | vec4 pos_new[2]; // *current* positions for vertex 0 (root) and vertex 1. 27 | 28 | pos_old_old[0] = g_HairVertexPositionsPrevPrev_[globalRootVertexIndex]; 29 | pos_old_old[1] = g_HairVertexPositionsPrevPrev_[globalRootVertexIndex + 1]; 30 | 31 | pos_old[0] = g_HairVertexPositionsPrev_[globalRootVertexIndex]; 32 | pos_old[1] = g_HairVertexPositionsPrev_[globalRootVertexIndex + 1]; 33 | 34 | pos_new[0] = g_HairVertexPositions_[globalRootVertexIndex]; 35 | pos_new[1] = g_HairVertexPositions_[globalRootVertexIndex + 1]; 36 | 37 | // 'down the strand' normalized vectors 38 | vec3 u = normalize(pos_old[1].xyz - pos_old[0].xyz); 39 | vec3 v = normalize(pos_new[1].xyz - pos_new[0].xyz); 40 | 41 | // Compute rotation and translation which transform pos_old to pos_new. 42 | // Since the first two vertices are immovable, we can assume that there 43 | // is no scaling during tranform. 44 | vec4 rot = QuatFromTwoUnitVectors(u, v); 45 | vec3 trans = pos_new[0].xyz - MultQuaternionAndVector(rot, pos_old[0].xyz); 46 | 47 | float vspCoeff = GetVelocityShockPropogation(); 48 | float vspAccelThreshold = GetVSPAccelThreshold(); // purely shock propagation driven threshold 49 | float restLength0 = g_HairRestLengthSRV_[globalRootVertexIndex]; 50 | 51 | // Increase the VSP coefficient by checking pseudo-acceleration 52 | // to handle over-stretching when the character moves very fast 53 | // (this is just A from Verlet Integration) 54 | float accel = length(pos_new[1] - 2.0 * pos_old[1] + pos_old_old[1]); 55 | if (accel > vspAccelThreshold){ // TODO: expose this value? 56 | vspCoeff = 1.0f; 57 | } 58 | 59 | // for all children vertices that are further from root then 1st vertex 60 | for (uint i = 2; i < numVerticesInTheStrand; i++) { 61 | uint globalVertexIndex = globalRootVertexIndex + i; // i := localVertexIndex 62 | 63 | vec4 pos_new_n = g_HairVertexPositions_[globalVertexIndex]; 64 | vec4 pos_old_n = g_HairVertexPositionsPrev_[globalVertexIndex]; 65 | 66 | // Using vspCoeff as a weight combine position from sim0_IntegrationAndGlobalShapeConstraints 67 | // and 'where it would be if we applied same (rotation + trans) that parent was subjected to'. 68 | // This essentially propagates some of the movement from parent to children 69 | vec3 pos_new_propagated = MultQuaternionAndVector(rot, pos_new_n.xyz) + trans; 70 | vec3 pos_old_propagated = MultQuaternionAndVector(rot, pos_old_n.xyz) + trans; 71 | pos_new_n.xyz = (1.f - vspCoeff) * pos_new_n.xyz 72 | + vspCoeff * pos_new_propagated; 73 | pos_old_n.xyz = (1.f - vspCoeff) * pos_old_n.xyz 74 | + vspCoeff * pos_old_propagated; 75 | 76 | // simple write back to where we red from in 1st place 77 | g_HairVertexPositions_[globalVertexIndex].xyz = pos_new_n.xyz; 78 | g_HairVertexPositionsPrev_[globalVertexIndex].xyz = pos_old_n.xyz; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/gl-tfx/TFxHairStrands.cpp: -------------------------------------------------------------------------------- 1 | #include "../../include/pch.hpp" 2 | #include "TFxHairStrands.hpp" 3 | #include "print_me.hpp" 4 | 5 | #include "../../libs/amd_tressfx/include/AMD_Types.h" 6 | #include "../../libs/amd_tressfx/include/TressFXCommon.h" 7 | #include "../../libs/amd_tressfx/include/TressFXGPUInterface.h" 8 | #include "GpuInterface/TFxGpuInterface.hpp" 9 | // #include "../../libs/amd_tressfx/include/TressFXAsset.h" 10 | #include "../../libs/amd_tressfx/include/TressFXHairObject.h" 11 | #include "../../libs/amd_tressfx/include/TressFXSimulation.h" 12 | 13 | // #include "SuAnimatedModel.h" 14 | // #include "SkeletonInterface.h" 15 | // #include "SushiGPUInterface.h" 16 | 17 | 18 | namespace glTFx { 19 | 20 | void TFxHairStrands::initialize( 21 | const char*const hairObjectName, 22 | const char*const tfxFilePath, 23 | // const char*const tfxboneFilePath, 24 | int numFollowHairsPerGuideHair, 25 | float tipSeparationFactor) 26 | { 27 | LOGD << "Loading '" << hairObjectName << "' from '" << tfxFilePath << "'"; 28 | 29 | EI_Device* pDevice = GetDevice(); 30 | EI_CommandContextRef uploadCommandContext = GetContext(); 31 | 32 | TressFXHairObject* hairObject = new TressFXHairObject; 33 | AMD::TressFXAsset* asset = new AMD::TressFXAsset(); 34 | 35 | // Load *.tfx 36 | // NOTE: asset will be destroyed after we upload data to GPU 37 | FILE * fp = fopen(tfxFilePath, "rb"); 38 | GFX_FAIL_IF(!fp, ".tfx file could not be found"); 39 | auto load_ok = asset->LoadHairData(fp); 40 | fclose(fp); 41 | GFX_FAIL_IF(!load_ok, "asset->LoadHairData returned false, some AMD internal problem when loading *.tfx file?"); 42 | 43 | asset->GenerateFollowHairs(numFollowHairsPerGuideHair, tipSeparationFactor, 1.2f); 44 | asset->ProcessAsset(); 45 | glTFx::debug::debug_asset(hairObjectName, *asset); 46 | LOGD << "Asset processing complete, will create hairObject (hairObject->Create)"; 47 | 48 | // Load *.tfxbone 49 | // SkeletonInterface skeletonData; 50 | // skeletonData.SetModel(modelName); 51 | // fp = fopen(tfxboneFilePath, "rb"); 52 | // asset->LoadBoneData(skeletonData, fp); 53 | // fclose(fp); 54 | // m_pSkeleton = dynamic_cast(SuObjectManager::GetRef().GetObjectByName(modelName)); 55 | 56 | 57 | // The color texture is only used as an srv. 58 | // But, TressFX only understands EI_Resource*, so we just wrap it in that. 59 | // As user of TressFX, we have defined EI_Resource to work with this. 60 | // EI_Resource colorTextureWrapper; 61 | // colorTextureWrapper.srv = colorTextureView; 62 | EI_SRV colorTextureWrapper = nullptr; 63 | 64 | hairObject->Create(asset, pDevice, uploadCommandContext, hairObjectName, colorTextureWrapper); 65 | m_pStrands = hairObject; 66 | 67 | delete asset; 68 | } 69 | 70 | void TFxHairStrands::destroy(EI_Device* pDevice) { 71 | if (m_pStrands) { 72 | m_pStrands->Destroy(pDevice); 73 | delete m_pStrands; 74 | } 75 | m_pStrands = nullptr; 76 | // m_pSkeketon is not owned by this object. 77 | } 78 | 79 | // 80 | 81 | void TFxHairStrands::TransitionSimToRendering(EI_CommandContextRef context) { 82 | m_pStrands->GetPosTanCollection().TransitionSimToRendering(context); 83 | } 84 | 85 | void TFxHairStrands::TransitionRenderingToSim(EI_CommandContextRef context) { 86 | m_pStrands->GetPosTanCollection().TransitionRenderingToSim(context); 87 | } 88 | 89 | /* 90 | void TFxHairStrands::update_bones(EI_CommandContextRef context) { 91 | const SuArray& boneMatrices = m_pSkeleton->GetSkinningMatrices(); 92 | const float* pBoneMatricesInWS = (const float32*)boneMatrices[0]; 93 | 94 | // update bone matrices for bone skinning of first two vertices of hair strands 95 | m_pStrands->UpdateBoneMatrices(context, pBoneMatricesInWS, 16 * sizeof(float) * boneMatrices.size()); 96 | } 97 | */ 98 | 99 | void TFxHairStrands::simulate(EI_CommandContextRef context, TressFXSimulation* pSimulation) { 100 | pSimulation->Simulate(context, *m_pStrands); 101 | } 102 | // 103 | 104 | } // namespace glTFx 105 | -------------------------------------------------------------------------------- /src/shaders/gl-tfx/sim/_SimParams.comp.glsl: -------------------------------------------------------------------------------- 1 | // START _SimParams.glsl 2 | 3 | // @see libs\amd_tressfx\include\TressFXSettings.h 4 | // @see tressfx-reference\TressFX-master\amd_tressfx_sample\bin\Scripts\GUI.lua 5 | 6 | // TressFXAsset RatBoy_body.mohawk{ 7 | // m_numTotalStrands: 6720 8 | // m_numTotalVertices: 215040 9 | // m_numVerticesPerStrand: 32 10 | // m_numGuideStrands: 2240 11 | // m_numGuideVertices: 71680 12 | // m_numFollowStrandsPerGuide: 2 13 | // has_skeleton: False 14 | // }; 15 | 16 | 17 | uniform vec4 g_Wind ; //= vec4(0,0,0,0); //vec4(150,0,0,0); 18 | uniform vec4 g_Wind1; //= vec4(0,0,0,0); 19 | uniform vec4 g_Wind2; //= vec4(0,0,0,0); 20 | uniform vec4 g_Wind3; //= vec4(0,0,0,0); 21 | 22 | uniform vec4 g_Shape; // damping, local stiffness, global stiffness, global range. 23 | uniform vec4 g_GravTimeTip; // gravity maginitude (assumed to be in negative y direction.) 24 | uniform ivec4 g_SimInts; // Length iterations, local iterations, collision flag. 25 | uniform ivec4 g_Counts; // num strands per thread group, num follow hairs per guid hair, num verts per strand. 26 | // uniform vec4 g_VSP; // VSP parmeters 27 | 28 | #define g_NumOfStrandsPerThreadGroup (g_Counts.x) // (2) THREAD_GROUP_SIZE(64) / VERTEX_PER_STRAND(32) in kernel/vertex (should not be used in kernel/strand, cause bs) 29 | #define g_NumFollowHairsPerGuideHair (g_Counts.y) // (2) 30 | // #define g_NumVerticesPerStrand (g_Counts.z) // 32 31 | // #define g_NumLocalShapeMatchingIterations 1 //g_SimInts.y 32 | #define g_GravityMagnitude (g_GravTimeTip.x) //(200.0) 33 | #define g_TimeStep (g_GravTimeTip.y) //(1.0 / 60.0) 34 | #define g_TipSeparationFactor (g_GravTimeTip.z) //(0.0) 35 | 36 | const float LENGTH_STIFFNESS = 1.0; // TODO make uniform? 37 | 38 | // unused 39 | uint GetStrandType(uint globalThreadIndex) { return 0; } 40 | 41 | // Used durring Verlet integration. Can be though of as inertia. 42 | // We calculate `delta = position_now - position_prev` and then 43 | // multiply by damping: 44 | // * if damping == 1, then delta affects outcome (seemingly another acceleration) 45 | // * if damping == 0, then delta is nullified and verlet only calculates 46 | // basing on forces/gravity 47 | float GetDamping(uint strandType) { 48 | return g_Shape.x; // 1.0f; 49 | } 50 | 51 | 52 | // 53 | // Global Shape Constraints (GSC) 54 | 55 | // If the forces/gravity are not strong enough to overcome 56 | // this, the strands will not move 57 | float GetGlobalStiffness(uint strandType) { 58 | return g_Shape.z; //0.05; 59 | } 60 | 61 | // By default, Global Shape Constraints affect only `global_range * vertices_in_strand` 62 | // vertices: 63 | // * globalRange == 1.0, then strand tips will be affected 64 | // by GSC, which wolud negate forces/gravity etc. 65 | // * globalRange == 0.0, then whole strand is affected by forces/gravity 66 | // * globalRange == 0.5, only half of strand (the one closer to root) 67 | // is affected by forces/gravity 68 | // Also known as 'globalShapeMatchingEffectiveRange' 69 | float GetGlobalRange(uint strandType) { 70 | return g_Shape.w; // 0.3; 71 | } 72 | 73 | 74 | // 75 | // Velocity Shock Propogation (VSP) 76 | 77 | // shock propagation weight: 78 | // * value == 0, then no VSP 79 | // * value == 1, then purely driven by shock propagation 80 | float GetVelocityShockPropogation() { return 0; } // g_VSP.x; } 81 | 82 | // purely shock propagation driven threshold 83 | float GetVSPAccelThreshold() { return 0; } // g_VSP.y; } 84 | 85 | 86 | // 87 | // Local Shape Constraints 88 | 89 | // * stiffness == 0, then no local shape preservation 90 | // * stiffness == 1, then ignore forces/gravity VSP etc. 91 | // NOTE: value gets halfed in shader code, so when You set it to 1, 92 | // it will actually still be 0.5. No, setting the value to 93 | // 2 will not help either (taken min(stiffness, 0.95)) 94 | float GetLocalStiffness(uint strandType) { 95 | return g_Shape.y; // 0.9; 96 | } 97 | 98 | 99 | 100 | 101 | int GetLengthConstraintIterations() { 102 | return int(g_SimInts.x); //1; 103 | } 104 | 105 | // int GetLocalConstraintIterations() { return int(g_SimInts.y); } 106 | 107 | // END _SimParams.glsl 108 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/TressFXShortCut.h: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Interface for the shortcut method. 4 | // ---------------------------------------------------------------------------- 5 | // 6 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | #ifndef AMD_TRESSFXSHORTCUT_H 28 | #define AMD_TRESSFXSHORTCUT_H 29 | 30 | 31 | #include "TressFXGPUInterface.h" 32 | 33 | #define TRESSFX_SHORTCUT_DEPTH_NODE_SIZE 4 34 | #define TRESSFX_SHORTCUT_K 3 35 | #define TRESSFX_SHORTCUT_INITIAL_DEPTH 0x3f800000 36 | 37 | // This is the interface the engine uses to call TressFX at a high level. 38 | // There are basically two steps each frame. 39 | // In the first, hair strands are rendered, accumulating the fragments in 40 | // the KBuffer: 41 | // BindForBuild() 42 | // [Draws hair] 43 | // DoneBuilding() 44 | // 45 | // In the second, the fragments are gathered and blended into the backbuffer. 46 | // BindForRead() 47 | // [Draw screen pass] 48 | // DoneReading() 49 | // 50 | class TressFXShortCut 51 | { 52 | public: 53 | TressFXShortCut(); 54 | ~TressFXShortCut(); 55 | 56 | // node size should include room for UINT next pointer. 57 | bool Create(EI_Device* pDevice, int width, int height); 58 | void Destroy(EI_Device* context); 59 | 60 | void Clear(EI_CommandContextRef context); 61 | 62 | 63 | // These might get removed. 64 | // Do we want to gather the bindings to be sent for each 65 | // draw, or just bind once? 66 | void BindForDepthsAlpha(EI_CommandContextRef context); 67 | void BindForResolveDepth(EI_CommandContextRef context); 68 | void BindForFillColors(EI_CommandContextRef context); 69 | void BindForResolveColor(EI_CommandContextRef context); 70 | 71 | // The "dones" should not require a layout if it's just a transition, 72 | // but this is an opportunity for unbinding. 73 | void DoneDepthsAlpha(EI_CommandContextRef context); 74 | void DoneResolveDepth(EI_CommandContextRef context); 75 | void DoneFillColors(EI_CommandContextRef context); 76 | void DoneResolveColor(EI_CommandContextRef context); 77 | 78 | EI_RWTexture2D* GetDepthsTexture() { return m_pDepths; } 79 | EI_RWTexture2D* GetInvAlphaTexture() { return m_pInvAlpha; } 80 | EI_RWTexture2D* GetColorsTexture() { return m_pColors; } 81 | 82 | private: 83 | int m_nScreenWidth; 84 | int m_nScreenHeight; 85 | 86 | // We track whether the current KBuffer is valid 87 | // so the engine implementation doesn't have to. 88 | bool m_bCreated; 89 | 90 | EI_RWTexture2D* m_pDepths; 91 | EI_RWTexture2D* m_pInvAlpha; 92 | EI_RWTexture2D* m_pColors; 93 | 94 | void CreateDepthsAlphaBindSet(EI_Device* pDevice); 95 | void CreateResolveDepthBindSet(EI_Device* pDevice); 96 | void CreateFillColorsBindSet(EI_Device* pDevice); 97 | void CreateResolveColorBindSet(EI_Device* pDevice); 98 | 99 | 100 | EI_BindSet* m_pShortCutDepthsAlphaBindSet; 101 | 102 | // These two are the same. Merge? 103 | EI_BindSet* m_pShortCutResolveDepthBindSet; 104 | EI_BindSet* m_pShortCutFillColorsBindSet; 105 | 106 | EI_BindSet* m_pShortCutResolveColorBindSet; 107 | }; 108 | 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /src/gl-tfx/GpuInterface/TFxGpuInterface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../include_TFx_pls_no_warnings.hpp" 4 | #include "../../../libs/amd_tressfx/include/AMD_TressFX.h" 5 | #include "../../../libs/amd_tressfx/include/TressFXGPUInterface.h" 6 | 7 | /* 8 | #include "SuCommandList.h" 9 | #include "SuGPUIndexBuffer.h" 10 | #include "SuGPUResourceManager.h" 11 | #include "SuGPUStructuredBuffer.h" 12 | #include "SuGPUTexture2DArray.h" 13 | #include "SuTextureSlot.h" 14 | #include "SuTextureSlotBinder.h" 15 | #include "SuUAVSlot.h" 16 | #include "SuUAVSlotBinder.h" 17 | #include "SuEffect.h" 18 | // For timers 19 | #include "SuRenderManager.h" 20 | */ 21 | 22 | enum class TFx_ResourceType { 23 | ClearableTexture2D, // TFx_cbCreate2D 24 | StructuredBufferRW_WithAtomicCounter, // read-write with additional space for uint 25 | StructuredBufferRW, // read-write 26 | StructuredBufferR // read 27 | }; 28 | 29 | struct ClearableTexture { 30 | glUtils::RawBuffer clear_data_buffer; 31 | glUtils::Texture texture; 32 | }; 33 | 34 | struct BufferWithCounter { 35 | glUtils::RawBuffer buffer; 36 | glUtils::RawBuffer counter; 37 | }; 38 | 39 | class EI_Resource { 40 | public: 41 | EI_Resource(); 42 | ~EI_Resource(){} // handled by pfDestroySB? anyway, not here 43 | 44 | TFx_ResourceType type; 45 | EI_StringHash name; 46 | 47 | union { 48 | ClearableTexture texture; 49 | glUtils::RawBuffer buffer; 50 | BufferWithCounter buffer_with_counter; 51 | }; 52 | // public: 53 | // SuGPUResourcePtr resource; 54 | // SuGPUUnorderedAccessViewPtr uav; 55 | // SuGPUSamplingResourceViewPtr srv; 56 | // SuGPURenderableResourceViewPtr rtv; 57 | }; 58 | 59 | // typedef glUtils::ShaderBlock SRVSlot; // SSBO (cause not known number of data) 60 | // typedef glUtils::ShaderBlock UAVSlot; // SSBO 61 | typedef glUtils::ShaderVariable EffectParameter; // TODO uniform not in UBO? or in UBO? check this! 62 | 63 | struct ShaderResource { 64 | ShaderResource() : is_block(false), variable(nullptr){} 65 | inline bool was_found_in_glsl () const noexcept {return shader != nullptr;} 66 | 67 | bool is_block; 68 | std::string name; 69 | glUtils::Shader* shader = nullptr; 70 | 71 | union { 72 | glUtils::ShaderBlock* block; 73 | const glUtils::ShaderVariable* variable; 74 | }; 75 | }; 76 | 77 | struct EI_BindLayout { 78 | // std::vector srvs; 79 | // std::vector uavs; 80 | std::vector srvs; 81 | std::vector uavs; 82 | std::vector constants; 83 | // SuArray srvs; 84 | // SuArray uavs; 85 | // SuArray constants; 86 | }; 87 | 88 | 89 | struct GlobalState; 90 | class EI_CommandContext { // ID3D11DeviceContext 91 | public: 92 | GlobalState* state = nullptr; 93 | TressFXHairObject* simulated_hair_object = nullptr; 94 | }; 95 | 96 | class EI_Device {}; 97 | 98 | struct ShaderMetadata { 99 | glUtils::Shader* shader = nullptr; 100 | std::string path_1; // vertex/compute shader 101 | std::string path_2; // fragment shader 102 | }; 103 | 104 | class EI_LayoutManager { 105 | public: 106 | std::vector shaders; 107 | }; 108 | 109 | class EI_BindSet { 110 | public: 111 | // NOTE: EI_SRV & EI_UAV are EI_Resource* 112 | std::vector srvs; // raw pointers to resources 113 | std::vector uavs; // this could backfire easily.. 114 | // int nSRVs; 115 | // EI_SRV* srvs; 116 | // int nUAVs; 117 | // EI_UAV* uavs; 118 | void* values; 119 | int nBytes; 120 | }; 121 | 122 | class EI_PSO { 123 | public: 124 | glUtils::Shader* shader = nullptr; 125 | glUtils::DrawParameters draw_params; 126 | }; 127 | 128 | class EI_IndexBuffer { 129 | public: 130 | std::string name; 131 | GLenum buffer_el_type; // GL_UNSIGNED_INT, GL_UNSIGNED_SHORT etc. 132 | // u32 m_nIndexSize; ///< Individual index element size (element size) 133 | u32 m_nIndexCount; ///< Number of indices in this index buffer (elements count) 134 | glUtils::RawBuffer buffer; 135 | GLuint vao_gl_id; 136 | }; 137 | 138 | namespace glTFx { 139 | 140 | EI_Device* GetDevice(); 141 | EI_CommandContextRef GetContext(); 142 | void load_tfx_shader (glUtils::Shader&, const glUtils::ShaderTexts& filenames); 143 | 144 | /** Has to be called during init somehow */ 145 | void init_TFx_callbacks(); 146 | 147 | } 148 | -------------------------------------------------------------------------------- /libs/amd_tressfx/src/TressFXSimulation.cpp: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------- 2 | // Invokes simulation compute shaders. 3 | // ---------------------------------------------------------------------------- 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | #include "AMD_TressFX.h" 27 | #include "TressFXSimulation.h" 28 | 29 | // TressFX 30 | #include "TressFXLayouts.h" 31 | #include "TressFXHairObject.h" 32 | 33 | void TressFXSimulation::Initialize(EI_Device* pDevice, EI_LayoutManagerRef simLayoutManager) 34 | { 35 | mVelocityShockPropagationPSO = EI_CreateComputeShaderPSO(pDevice, simLayoutManager, TRESSFX_STRING_HASH("VelocityShockPropagation")); 36 | mIntegrationAndGlobalShapeConstraintsPSO = EI_CreateComputeShaderPSO(pDevice, simLayoutManager, TRESSFX_STRING_HASH("IntegrationAndGlobalShapeConstraints")); 37 | mLocalShapeConstraintsPSO = EI_CreateComputeShaderPSO(pDevice, simLayoutManager, TRESSFX_STRING_HASH("LocalShapeConstraints")); 38 | mLengthConstriantsWindAndCollisionPSO = EI_CreateComputeShaderPSO(pDevice, simLayoutManager, TRESSFX_STRING_HASH("LengthConstriantsWindAndCollision")); 39 | mUpdateFollowHairVerticesPSO = EI_CreateComputeShaderPSO(pDevice, simLayoutManager, TRESSFX_STRING_HASH("UpdateFollowHairVertices")); 40 | } 41 | 42 | void TressFXSimulation::Shutdown(EI_Device* pDevice) 43 | { 44 | EI_DestroyPSO(pDevice, mVelocityShockPropagationPSO); 45 | EI_DestroyPSO(pDevice, mIntegrationAndGlobalShapeConstraintsPSO); 46 | EI_DestroyPSO(pDevice, mLocalShapeConstraintsPSO); 47 | EI_DestroyPSO(pDevice, mLengthConstriantsWindAndCollisionPSO); 48 | EI_DestroyPSO(pDevice, mUpdateFollowHairVerticesPSO); 49 | } 50 | 51 | void TressFXSimulation::Simulate(EI_CommandContextRef commandContext, TressFXHairObject& hairObject) 52 | { 53 | // For dispatching one thread per one vertex 54 | int numOfGroupsForCS_VertexLevel = (int)((float)hairObject.m_NumTotalVertice / (float)TRESSFX_SIM_THREAD_GROUP_SIZE); 55 | 56 | // For dispatching one thread per one strand 57 | int numOfGroupsForCS_StrandLevel = (int)(((float)(hairObject.m_NumTotalStrands) / (float)TRESSFX_SIM_THREAD_GROUP_SIZE)); 58 | 59 | 60 | // IntegrationAndGlobalShapeConstraints 61 | { 62 | EI_Dispatch(commandContext, *mIntegrationAndGlobalShapeConstraintsPSO, numOfGroupsForCS_VertexLevel); 63 | hairObject.mPosTanCollection.UAVBarrier(commandContext); 64 | } 65 | 66 | // VelocityShockPropagation 67 | { 68 | EI_Dispatch(commandContext, *mVelocityShockPropagationPSO, numOfGroupsForCS_StrandLevel); 69 | hairObject.mPosTanCollection.UAVBarrier(commandContext); 70 | } 71 | 72 | // LocalShapeConstraintsWithIteration 73 | for (int i = 0; i < hairObject.m_CPULocalShapeIterations; i++) 74 | { 75 | EI_Dispatch(commandContext, *mLocalShapeConstraintsPSO, numOfGroupsForCS_StrandLevel); 76 | hairObject.mPosTanCollection.UAVBarrier(commandContext); 77 | } 78 | 79 | // LengthConstriantsWindAndCollision 80 | { 81 | EI_Dispatch(commandContext, *mLengthConstriantsWindAndCollisionPSO, numOfGroupsForCS_VertexLevel); 82 | hairObject.mPosTanCollection.UAVBarrier(commandContext); 83 | } 84 | 85 | // UpdateFollowHairVertices 86 | { 87 | EI_Dispatch(commandContext, *mUpdateFollowHairVerticesPSO, numOfGroupsForCS_VertexLevel); 88 | hairObject.mPosTanCollection.UAVBarrier(commandContext); 89 | } 90 | 91 | hairObject.mSimulationFrame++; 92 | } 93 | -------------------------------------------------------------------------------- /libs/amd_tressfx/include/Math/Vector3D.h: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // File: Vector3D.h 3 | // 4 | // 5 | // Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | //-------------------------------------------------------------------------------------- 26 | 27 | #pragma once 28 | 29 | #pragma warning(push) 30 | #pragma warning( \ 31 | disable : 4201) // disable warning C4201: nonstandard extension used : nameless struct/union 32 | 33 | #include 34 | 35 | namespace AMD 36 | { 37 | class tressfx_vec3 38 | { 39 | public: 40 | union 41 | { 42 | struct 43 | { 44 | float m[4]; 45 | }; // x, y, z, w 46 | struct 47 | { 48 | float x, y, z, w; 49 | }; 50 | }; 51 | 52 | tressfx_vec3() 53 | { 54 | x = y = z = 0; 55 | w = 1.f; 56 | } 57 | 58 | tressfx_vec3(float x, float y, float z) 59 | { 60 | m[0] = x; 61 | m[1] = y; 62 | m[2] = z; 63 | }; 64 | tressfx_vec3(float* xyz); 65 | tressfx_vec3(const tressfx_vec3& other); 66 | tressfx_vec3(const tressfx_vec3& begin, const tressfx_vec3& end); 67 | ~tressfx_vec3(){}; 68 | 69 | public: 70 | tressfx_vec3& Normalize(); 71 | tressfx_vec3 NormalizeOther() const; 72 | tressfx_vec3 Cross(const tressfx_vec3& v) const 73 | { 74 | return tressfx_vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); 75 | }; 76 | float Dot(const tressfx_vec3& v) const { return x * v.x + y * v.y + z * v.z; }; 77 | float Length() const { return sqrt(x * x + y * y + z * z); }; 78 | float LengthSqr() const { return (x * x + y * y + z * z); }; 79 | void Set(float xIn, float yIn, float zIn) 80 | { 81 | m[0] = xIn; 82 | m[1] = yIn; 83 | m[2] = zIn; 84 | }; 85 | 86 | const float& operator[](unsigned int i) const { return m[i]; } 87 | float& operator[](unsigned int i) { return m[i]; } 88 | 89 | tressfx_vec3& operator=(const tressfx_vec3& other); 90 | tressfx_vec3& operator=(float val); 91 | tressfx_vec3& operator=(float* xyz); 92 | bool operator!=(float val) const; 93 | bool operator<(float val) const; 94 | bool operator>(float val) const; 95 | bool operator==(float val) const; 96 | bool operator==(const tressfx_vec3& other) const; 97 | bool operator!=(const tressfx_vec3& other) const; 98 | tressfx_vec3& operator-=(const tressfx_vec3& other); 99 | tressfx_vec3& operator+=(const tressfx_vec3& other); 100 | tressfx_vec3& operator*=(float val); 101 | tressfx_vec3 operator-(const tressfx_vec3& other) const; 102 | tressfx_vec3 operator+(const tressfx_vec3& other) const; 103 | tressfx_vec3 operator/(float val) const; 104 | tressfx_vec3 operator*(float val) const; 105 | float operator*(const tressfx_vec3& other) const; 106 | 107 | friend tressfx_vec3 operator*(float val, const tressfx_vec3& other); 108 | friend tressfx_vec3 operator-(const tressfx_vec3& other); 109 | }; 110 | 111 | } // namespace AMD 112 | 113 | #pragma warning(pop) 114 | --------------------------------------------------------------------------------